Function decorators allow us to modify the behavior of a function or method without having to change the source code of the function being decorated.
They are used to wrap a function, modify its behavior, and return the modified function or a new function with the same or different name.
Decorators are quite common in Python and programming in general, Python offers an easier and more convenient syntax to work with them. The syntax as shown below:
@decorator_function def function_to_decorate(): <block>
copy
A decorator function is a higher order function that takes a function as an argument and returns a new function commonly referred to as a wrapper . The wrapper function is used to modify or extend the behavior of the original function, it is also responsible of invoking the original function.
Without using the short hand syntax, we would need to explicitly pass the function to decorate as an argument to the decorator function, as shown below:
When you call a decorated function with arguments, the arguments are first passed to the wrapper function, which then forwards them to the original function.
If the wrapper function does not define any parameters and arguments are given to the decorated function, an error will be raised .
It is common to define wrapper functions which take arbitrary arguments as shown below:
A timing decorator function:
Decorator functions with arguments:
Decorator functions can also take additional arguments besides the function being decorated. The syntax of calling such a decorator is as shown below;
@my_decorator(arguments) def my_function(): <block>
copy
Defining a decorator function that takes additional arguments requires a slightly different syntax. Instead of defining the decorator function to take a single function as an argument, we define it to take any number of arguments, including the function being decorated. Then we define an inner function that takes the function as its argument and returns a wrapper function that uses the additional arguments passed to the decorator. Example:
Multiple decorator functions
When multiple decorations are applied to a Python function, they are evaluated and applied in the order in which they appear. The first decoration will wrap the original function, and each successive decoration will wrap the result of the previous decoration. This means that the innermost decorator will be evaluated and applied first, followed by the decorators that wrap it from the outside in. Example:
When to use decorator Functions
Decorators can be used to add extra functionality to an existing function, such functionality can include:
- Logging
- Caching
- Rate limiting
- Authentication/Authorization
- Input/Output Sanitization
- Executing functions in parallel.
- Adding additional features to functions like argument binding, error handling and retry logic.
- Adding context managers to functions.