Decorators That Take Arguments in Python 2026 – Best Practices
Decorators that accept arguments are also called **decorator factories**. They are more powerful than simple decorators because you can customize their behavior when applying them. In 2026, this pattern is widely used for configurable decorators like retry logic, rate limiting, caching with TTL, and logging levels.
TL;DR — Structure of a Decorator with Arguments
- Outer function receives the decorator arguments
- Middle function is the actual decorator
- Inner function is the wrapper
- Always use
@wrapsin the innermost wrapper
1. Complete Example – repeat Decorator
from functools import wraps
from typing import Callable, Any
def repeat(times: int = 2):
"""Decorator factory that repeats a function multiple times."""
def decorator(func: Callable) -> Callable:
@wraps(func)
def wrapper(*args: Any, **kwargs: Any) -> Any:
result = None
for i in range(times):
print(f"Execution {i+1}/{times}")
result = func(*args, **kwargs)
return result
return wrapper
return decorator
2. Usage Examples
@repeat(3)
def greet(name: str):
print(f"Hello, {name}!")
greet("Alice")
# Output:
# Execution 1/3
# Hello, Alice!
# Execution 2/3
# Hello, Alice!
# Execution 3/3
# Hello, Alice!
@repeat(5)
def roll_dice():
import random
return random.randint(1, 6)
print("Final roll:", roll_dice())
3. Another Real-World Example – timeout Decorator
def timeout(seconds: float = 5.0):
def decorator(func: Callable):
@wraps(func)
def wrapper(*args, **kwargs):
import signal
def handler(signum, frame):
raise TimeoutError(f"Function {func.__name__} timed out after {seconds} seconds")
signal.signal(signal.SIGALRM, handler)
signal.alarm(int(seconds))
try:
return func(*args, **kwargs)
finally:
signal.alarm(0)
return wrapper
return decorator
@timeout(2.0)
def long_operation():
import time
time.sleep(3)
return "Done"
4. Best Practices in 2026
- Use clear, descriptive names for the outer function (decorator factory)
- Always include
@wraps(func)in the innermost wrapper - Provide sensible default values for decorator arguments
- Document what each argument does
- Keep the logic inside the wrapper as lightweight as possible
Conclusion
Decorators that take arguments (decorator factories) are much more flexible than simple decorators. In 2026, mastering this pattern allows you to create powerful, reusable, and configurable tools such as retry, rate limiting, caching, and validation decorators.
Next steps:
- Try converting your existing simple decorators into ones that accept parameters
- Related articles: Decorators in Python 2026 • Decorators and Metadata Preservation in Python 2026 • Writing Functions in Python 2026