- Expert Python Programming(Third Edition)
- Micha? Jaworski Tarek Ziadé
- 241字
- 2021-06-24 14:55:06
Parametrizing decorators
In real usage scenarios, there is often a need to use decorators that can be parameterized. When the function is used as a decorator, then the solution is simple – a second level of wrapping has to be used. Here is a simple example of the decorator that repeats the execution of a decorated function the specified number of times every time it is called:
def repeat(number=3): """Cause decorated function to be repeated a number of times. Last value of original function call is returned as a result.
:param number: number of repetitions, 3 if not specified """ def actual_decorator(function): def wrapper(*args, **kwargs): result = None for _ in range(number): result = function(*args, **kwargs) return result return wrapper return actual_decorator
The decorator that's defined this way can accept parameters:
>>> @repeat(2)
... def print_my_call():
... print("print_my_call() called!")
...
>>> print_my_call()
print_my_call() called!
print_my_call() called!
Note that, even if the parameterized decorator has default values for its arguments, the parentheses after its name is required. The correct way to use the preceding decorator with default arguments is as follows:
>>> @repeat() ... def print_my_call(): ... print("print_my_call() called!") ... >>> print_my_call()
print_my_call() called!
print_my_call() called!
print_my_call() called!
Missing these parentheses will result in the following error when the decorated function is called:
>>> @repeat ... def print_my_call(): ... print("print_my_call() called!") ... >>> print_my_call()
Traceback (most recent call last): File "<input>", line 1, in <module> TypeError: actual_decorator() missing 1 required positional argument: 'function'