Python Decorators With Arguments
A decorator factory is a function that takes settings and returns a decorator.
Layer one takes the setting
The outer function is the factory. This first sketch only passes the function through.
def repeat(times):
def decorator(func):
return func
return decoratorLayers two and three do the work
The decorator receives the function. The wrapper runs it the requested number of times.
from functools import wraps
def repeat(times):
def decorator(func):
@wraps(func)
def wrapper():
for _ in range(times):
func()
return wrapper
return decoratorCall the factory in the @ line
The brackets call the factory first. Its returned decorator then wraps greet.
@repeat(times=2)
def greet():
print("Hello!")
greet()A second factory takes a label
The tag factory works the same way. Its setting is a word instead of a number.
def tag(label):
def decorator(func):
@wraps(func)
def wrapper():
print("[" + label + "]")
func()
return wrapper
return decoratorUse the label factory
The label prints before the function runs. The function keeps its own job.
@tag("sale")
def show_item():
print("Red shoes: 40")
show_item()Example
from functools import wraps
def repeat(times):
def decorator(func):
@wraps(func)
def wrapper():
for _ in range(times):
func()
return wrapper
return decorator
def tag(label):
def decorator(func):
@wraps(func)
def wrapper():
print("[" + label + "]")
return func()
return wrapper
return decorator
@repeat(times=3)
def cheer():
print("Go team!")
@tag("sale")
def show_item():
print("Red shoes: 40")
return "shown"
cheer()
result = show_item()
print(result)
print(cheer.__name__)Key points
- Decorator factory: a function that takes settings and returns a decorator
- Three layers: the factory takes settings, the decorator takes the function, the wrapper runs the call
- Use a decorator factory when a decorator needs a count, a label, or another setting
- The factory call runs before decoration.
- Its result is the decorator that wraps the function.
- Optional-argument decorators work with or without brackets.
- Treat that form as a tricky variant.
In this example, repeat and tag are both decorator factories. Calling repeat with 3 returns a decorator. That decorator wraps cheer in a looping wrapper. Calling tag with "sale" returns another decorator. That decorator wraps show_item in a labelling wrapper. The cheer call prints its line three times. The show_item call prints its label first. It then prints the item and returns a word. The final prints show that returned word. They also show the preserved function name.
Note
Writing @repeat alone passes the function as times.
Always call the factory, as in @repeat(times=3).
Try it Yourself
Edit the code, then press Run.
Running is simulated · Python Playground
Exercise
In @repeat(times=3), what does repeat(times=3) return?