Decorators are a structural design pattern which wrap the original object, to add extra functionality dynamically, without modifying the original object. Decorators are usually used to run code before and/or after a function. Thus, they decorate the function with additional functionality, without changing the original function. They can also be used to alter the functionality of methods and classes.
Functions in Python are first class objects: they can be assigned to variables, passed into functions as arguments, returned from functions and declared inside functions.
With that in mind, a decorator can be created using functions or classes.
Decorator using Functions
The general syntax for creating a decorator using functions is as follows:
original_function(), in this case, is the function that is decorated with the
For example, a decorator that upper cases the returned values from any function can be created as follows:
Decorator using Classes
The general syntax for creating a decorator using classes is as follows:
For example, a decorator created using class based syntax that upper cases the return values from any function:
Applying Decorator to a Function
The decorators created above accept an argument called
original_function which can be any function. Therefore, we create a
greeting() function and decorate it with the
greeting() function can be decorated with the common python syntax by calling the decorator function and assigning the result back to
However, Python provides a simpler way to achieve the same result using the
@ symbol syntax. Add the line
@upper_case_decorator at the start of function definition to decorate it.
@upper_case_decorator_with_class can be used to decorate other functions as well.
The full code with a decorator created using function will be:
Passing arguments to the Decorated functions
Arguments can be passed to the original function by creating parameters in the
arg1 is the parameter that the original function
greeting() requires. Thus, the
wrapper() function receives it and passes it along to the original function call.
General purpose decorators can be also be created that can accept any number of arguments by packing positional arguments using
*args and by packing keyword arguments using
An example of variable arguments accepting decorator is as follows:
Passing Arguments to Decorators
Arguments can also be passed to the decorator itself. To pass arguments to the decorator, there should be a
decorator_wrapper_to_accept_decorator_arguments() function wrapping the original decorator.
Eg: With the greeting function, the decorator could be setup to use a
number_of_times_to_greet parameter to greet once or more than once.
greeting_twice() have the exact same function definition, their outputs are different because the decorator is executing these functions as per the
number_of_times_to_greet argument passed to the decorator.
help() with Decorators
The original function name and docstring are lost when it’s wrapped by a decorator.
The name of the function is
greeting() and not
wrapper(). The decorator completely hides the function and it’s docstring. This also means that the
help(greeting) call will be completely useless since it’ll have no information about the
To solve this problem, python provides a decorator.
@functools.wraps() decorator can be used to decorate the
Decorators can be used to measure the performance of a function
Decorators are used to create specialized functions
Special functions like ‘once’ that would only execute one time even if they’re called more than once, can be created using decorators.