A decorator is the name used for a software design pattern. Decorators dynamically alter the functionality of a function, method, or class without having to directly use subclasses or change the source code of the function being decorated.
Decorators allow you to make simple modifications to callable objects like functions, methods, or classes.
The first assumption is
- “A decorator is a function that alter another function.”
Let’s go ahead
- A decorator receive as an input the function that will be decorated.
- The decorator after altered the function, will return the decorated function.
the following few lines show a simple decorator:
def fun_decorator(fun_to_be_decorated): fun_to_be_decorated.info = "decorated" return fun_to_be_decorated def myfunc(): print("myfunc") print(myfunc.info)
On the shell
>>> myfunc >>> myfunc() myfunc Traceback (most recent call last): File "", line 1, in File "", line 7, in myfunc print(myfunc.info) AttributeError: 'function' object has no attribute 'info' >>>
Now we are going to apply the decorator
>>> decorated = fun_decorator(myfunc) >>> decorated >>> myfunc
And the output produced is a just bit different:
>>> decorated() myfunc decorated >>> >>> myfunc() myfunc decorated >>>
Going ahead….
Simple decorator with a wrapper function
A wrapper if a function defined inside the decorator function that “wraps” the function to be decorated. In such a way it provides the capability to execute code before and after the function to be decorated.
from functools import wraps def fun_wrapper_decorator(fun_to_be_decorated): @wraps(fun_to_be_decorated) def wrapper(*args, **kwargs): print("before") fun_to_be_decorated() print("after") return wrapper @fun_wrapper_decorator def myfunc1(): print("myfunc")
As you can see from the code above, the “@” keyword can be used to apply the decorator to a function.
let’s give a try using the shell:
>>> myfunc1() before myfunc after
more decorators can be used in cascade, and they will be run in cascade, for example let’s add a second decorator to the code. The new code will be as follows:
from functools import wraps def fun_wrapper_decorator1(fun_to_be_decorated): @wraps(fun_to_be_decorated) def wrapper(*args, **kwargs): print("before1") fun_to_be_decorated() print("after1") return wrapper def fun_wrapper_decorator(fun_to_be_decorated): @wraps(fun_to_be_decorated) def wrapper(*args, **kwargs): print("before") fun_to_be_decorated() print("after") return wrapper @fun_wrapper_decorator1 @fun_wrapper_decorator def myfunc1(): print("myfunc")
and from the shell:
>>> myfunc1() before1 before myfunc after after1
Simple and powerful, next time we will see some real code.
Take a look at “Python decorators in the real world” for more about python decorators.
Gg1