In the previous articles on the Python decorator series, we have learnt decorators, how they work and to implement a simple function based decorator and a class based decorator. In this article we will learn to create decorators that supports parameters.
Function based decorator with parameters
from functools import wraps
def hello_decorator(num):
"""Simple decorator function that supports parameters"""
def inner_func(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""Simple decorator wrapper function"""
result = func(*args, **kwargs)
result = result + num
return result
return wrapper
return inner_func
@hello_decorator(100)
def add(a, b):
"""Simple function that returns sum of two numbers"""
return a + b
@hello_decorator(200)
def multiply(a, b):
"""Simple function that returns multiplication of two numbers"""
return a * b
if __name__ == '__main__':
output1 = add(2, 2)
print('Result:: ', output1)
print("=" * 25)
output2 = multiply(4, 2)
print('Result:: ', output2)
As you notice, the structure is little different from our previous examples,
- decorator takes a parameter
@hello_decorator(100)
- this is how we can pass arguments to our decorator -
hello_decorator
function returns an inner function. -
inner_func
takes the function to be decorated as an argument and returns the wrapper function. - wrapper function executes the
add
function and manipulates the output based on argumentresult = result + num
and returns the final result
Class based decorator with parameters
from functools import wraps
class HelloDecorator:
"""Simple class decorator"""
def __init__(self, num):
self.num = num
def __call__(self, func):
@wraps(func)
def wrapper(*args, **kwargs):
"""Simple class call method"""
result = func(*args, **kwargs)
result = result + self.num
return result
return wrapper
@HelloDecorator(100)
def add(a, b):
"""Simple function that returns sum of two numbers"""
return a + b
@HelloDecorator(200)
def multiply(a, b):
"""Simple function that returns multiplication of two numbers"""
return a * b
if __name__ == '__main__':
output1 = add(2, 2)
print('Result:: ', output1)
output2 = multiply(4, 2)
print('Result:: ', output2)
This class based decorator with parameters is pretty much similar to our simple function based decorator. The best thing with this method is, we do not need the extra boilerplate code to fix the doc strings.
So now to implement decorator with arguments, I would prefer class based approach. since it is very intuitive and doesn't requires an additional inner function and additional boilerplate code fixes for docs.
So far, we've covered the basic decorator implementation with examples. In the next article, we will implement various kinds decorator recipes. Stay tuned for upcoming articles. Subscribe to the newsletter and Connect with me on twitter to get my future articles.