Python > Advanced Python Concepts > Decorators > Function Decorators
Decorator with Arguments
This example shows how to create a decorator that accepts arguments. This allows you to customize the behavior of the decorator based on the arguments passed to it. The snippet demonstrates a decorator that can be used to repeat a function's execution a specified number of times.
Decorator with Arguments Structure
This code defines a decorator `repeat` that takes `num_times` as an argument. It returns another decorator function `decorator_repeat` which takes the function to be decorated `func` as argument. Inside `decorator_repeat`, a wrapper function is defined that executes the original function `num_times` times. `functools.wraps` is used to preserve the original function's metadata. The `@repeat(num_times=3)` syntax applies the decorator to the `greet` function, causing it to be executed three times.
import functools
def repeat(num_times):
def decorator_repeat(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator_repeat
@repeat(num_times=3)
def greet(name):
print(f'Hello, {name}!')
greet('World')
Concepts Behind the Snippet
This decorator leverages the concept of closures. The `decorator_repeat` function 'closes over' the `num_times` variable from the outer `repeat` function. This allows the wrapper function to access the `num_times` value even after the `repeat` function has completed execution. This is crucial for customizing the decorator's behavior based on arguments.
Real-Life Use Case Section
Decorators with arguments are useful for configuring aspects like retry counts, connection timeouts, logging levels, or access control rules. For instance, you might have a `@retry(max_retries=5, delay=2)` decorator to automatically retry a function that might fail due to temporary network issues.
Best Practices
Always use `functools.wraps` to preserve the metadata of the original function. This is even more important when dealing with decorators that take arguments, as debugging becomes significantly harder without the correct metadata. Ensure your arguments are named clearly to avoid confusion.
Interview Tip
Explain the different levels of nesting in the decorator definition and the role of each function (the outer function takes the decorator arguments, the middle function takes the function to be decorated, and the inner function is the wrapper). Practice writing decorators with arguments from scratch.
When to use them
Use decorators with arguments when you need to parameterize the behavior of the decorator based on specific requirements. This allows you to create more flexible and reusable decorators that can be adapted to different situations.
Memory footprint
The memory footprint is similar to simple decorators but with the addition of storing the decorator arguments. The overall impact remains relatively small unless large amounts of data are passed as arguments to the decorator.
Alternatives
Alternatives are limited if you need to customize the decorator's behavior. Manually wrapping functions becomes cumbersome, especially if you have multiple configurable options. Using class-based decorators is another option, but can be more verbose for simple cases.
Pros
Decorators with arguments offer increased flexibility and configurability. They allow you to tailor the behavior of the decorator to specific needs without modifying the original function's code. This makes them highly reusable and adaptable.
Cons
Decorators with arguments can be more complex to understand and implement than simple decorators. The nested structure can make the code harder to read and debug if not properly documented. Carefully consider whether the added complexity is justified by the increased flexibility.
FAQ
-
Why do I need three nested functions?
The outer function takes the arguments for the decorator, the middle function takes the function to be decorated, and the inner function (the wrapper) adds the functionality before and after the function call. -
Can I use default values for the decorator arguments?
Yes, you can define default values for the arguments in the outer function, just like with regular functions.