In Python, a decorator is any callable Python object used to modify a class or function. It takes a function, adds some functionality to it, and returns it. Decorators are primarily useful when you want to extend any existing function without any modification to the original function. Decorators are commonly used to add functionality to existing functions, such as logging, timing, or authentication.
- Decorators are called before the function call.
- It extends the functionality of our original functions without altering their source code.
- Decorators can be of two types:
- Function Decorators
- Class Decorators
Python Function Decorator Example
Function-based decorators are the easiest way to implement decorators in Python. A function-based decorator takes a function as an argument and returns a new function that wraps the original function.
Let’s create a decorator. First, we create one outer function and another inner function inside it. Here we are creating
sample_ecorator the outer function and
example_function as the inner function.
This outer function returns the inner function at the end of the outer function and inside the inner function, we will add our functionality before and after a
function (that we want to extend or add new functionality, in our case that function is the
Basically, a python decorator takes a function as input and adds some functionality before and after, and returns it back.
# Create a decorator def sample_decorator(func): # define the inner function def example_function(number): print("Before Funciton Call:", func.__name__) # call original function results = func(number) print("Cube: ", results) print("After Funciton Call:", func.__name__) # Return inner function return example_function def cube(num): return num**3 # decorate the function decorated_func = sample_decorator(cube) # call the decorated function decorated_func(2)
Output: Before Funciton Call: cube 8 After Funciton Call: cube
Let’s do it in a more compact way. Instead of assigning the function call to a variable, python has the functionality to do this in a simpler and more attractive way by using @ symbol above the function definition with the decorator name.
def sample_decorator(func): def example_function(number): print("Before Funciton Call:", func.__name__) results = func(number) print(results) print("After Funciton Call:", func.__name__) return example_function @sample_decorator def cube(num): return num**3 cube(2)
Output: Before Funciton Call: cube 8 After Funciton Call: cube In this example,
sample_decoratoris the name of the decorator function. When the code is executed, the function
cubeis passed as an argument to
sample_decorator, and the decorated function is then called.
Python Class Decorator Example
Decorators have the capability to modify the behavior of any python function or class. Class-based decorators are a more advanced way to implement decorators in Python. In this section, we will define decorator as a class. For defining this, we will use a __call__() method and pass the function to __init__ as an argument. It allows a class instance to behave like a function. For example, consider the following code example that implements a cube decorator using a class:
class CubeDecorator: def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): # before function print("Before Funciton Call:", self.func.__name__) # call original function cube_value = self.func(*args, **kwargs) print("Cube:", cube_value) # after function print("After Funciton Call:", self.func.__name__) return cube_value # Add class decorator @CubeDecorator def cube(num): return num**3 cube(20)
Output: Before Funciton Call: cube Cube: 8000 After Funciton Call: cube
After decoration, the call method of the class is called instead of the cube() method.
Real-life Decorator Example
Let’s see one real-life decorator example to calculate the execution time of a function. For example, consider the following code example that implements a
from time import time, sleep # Create a decorator def execution_time(func): # define the inner function def wrapper(*args, **kwargs): # get current time before execution t = time() # call function func(*args, **kwargs) # compute time difference print(func.__name__, ' function execution time: ', time() - t) return wrapper @execution_time def cube(num): return num**3 cube(3)
Output: cube function execution time: 2.1457672119140625e-06
The wrapper function of the execution_time decorator calculates the time difference between the before and after the function execution and prints the execution time of the function on the console using the time module.
Python decorators are the most useful functionality that allows programmers to expand the functionality of a function, class, or method by wrapping it with another function. Decorators mostly used real-life applications such as logging, testing, timing, and authentication. Python has the functionality to add decorators in a simpler and more attractive way by using @ symbol above the function definition with the decorator name.
We can implement decorators using either a function or a class. Function-based decorators take a function as an argument and return a new function that wraps the original function, while class-based decorators use the __call__ method to allow a class instance to behave like a function.