Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can one attach a decorator to a function "after the fact" in python?

Tags:

The way I understand decorators of function in python (and I might be wrong), is that they are supposed to add side effects and modify the return value of a function. Now decorators are added above the function definition of the function to be decorated or by an assignment. Here is a small example:

def print_args_decor(function):     def wrapper(*args, **kwargs):         print 'Arguments:', args, kwargs         # Added side-effect         return function(*args, **kwargs)*5       # Modified return value     return wrapper  @print_args_decor def do_stuff(strg, n=10):     """Repeats strg a few times."""     return strg * n  new_decorated_func = print_args_decor(do_stuff)  # Decoration by assignment  print do_stuff('a', 2) # Output: aaaaaaaaaa 

Now, how does one attach a decorator to a function defined elsewhere, ideally retaining the original function's name and docstring (like functools.wraps does)? For example, I'm importing the sqrt() function from Python's math module, and want to decorate it, how do I go about that?

from functools import wraps from math import sqrt  def print_args_decor(function):     @wraps(function)     def wrapper(*args, **kwargs):         print 'Arguments:', args, kwargs         # Added side-effect         return function(*args, **kwargs)*5       # Modified return value     return wrapper  # Decorate the sqrt() function from math module somehow @print_args_decor #??? sqrt #???  print sqrt(9)    # Output:  # Arguments: ([9],) {} # 15                   # <--- sqrt(9)*5 

How about decorate methods within classes after the fact? How about decorating classes themselves?

like image 990
con-f-use Avatar asked Nov 23 '15 10:11

con-f-use


People also ask

Can we use decorator inside a function in Python?

Nesting means placing or storing inside the other. Therefore, Nested Decorators means applying more than one decorator inside a function. Python allows us to implement more than one decorator to a function. It makes decorators useful for reusable building blocks as it accumulates the several effects together.

Can a function have two decorators Python?

Multiple decorators can be chained in Python. This is to say, a function can be decorated multiple times with different (or same) decorators.

Which symbol is used for adding decorators in Python?

Decorators. The main use case of the symbol @ in Python are decorators. In Python, a decorator extends the functionality of an existing function or class.


1 Answers

You imported sqrt into your module, just apply the decorator there in your own global namespace:

sqrt = print_args_decor(sqrt) 

This sets the name sqrt in your module namespace to the result of the decorator. There is no requirement that sqrt was originally defined in this module.

It is up to the decorator to uses the functools.wraps() decorator to preserve function metadata such as the name and docstring.

Decorating a class is no different in this respect:

ClassName = decorator(ClassName) 

On Python 2, for methods you need to be careful to grab the original unbound function; easiest is to use the method.__func__ attribute:

try:     # Python 2     ClassName.function_name = decorator(ClassName.function_name.__func__) except AttributeError:     # Python 3     ClassName.function_name = decorator(ClassName.function_name) 

I've wrapped the above in a try...except to make the pattern work across Python versions. The alternative is to grab the function object out of the class __dict__ to avoid the descriptor protocol from kicking in:

ClassName.function_name = decorator(ClassName.__dict__['function_name']) 
like image 142
Martijn Pieters Avatar answered Sep 30 '22 07:09

Martijn Pieters