Introduction
In Python, a decorator is a design pattern that provides a flexible and concise way to modify the functionality of functions without directly altering their source code. Decorators achieve this by dynamically wrapping a function within another function, often adding or extending its behavior. They are a cornerstone of Python's expressiveness and promote clean code separation.
Basic Structure
A decorator is essentially a callable (usually a function) that accepts another function as its argument. It then defines an inner function (often called a wrapper) and returns this inner function. The wrapper function incorporates the additional behavior you want to introduce.
Illustrative Example
def my_decorator(func):
def wrapper(*args, **kwargs):
print("Something happens before the function is called.")
result = func(*args, **kwargs) # Call the original function
print("Something happens after the function is called.")
return result
return wrapper
@my_decorator # Applying the decorator
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Alice")
Explanation
- The Decorator: The
my_decorator
function is the decorator. It takes a function (func
) as its input. - Inner Function: The
wrapper
function is defined inside the decorator. It encapsulates the extra code you want to execute before and after the original function. - Decorator Syntax: The
@my_decorator
line concisely applies the decorator to thesay_hello
function. It's equivalent to writingsay_hello = my_decorator(say_hello)
.
Common Use Cases
- Logging: Record function calls, arguments, and return values.
- Timing: Measure the execution time of functions.
- Authentication and Authorization: Restrict access to functions based on user roles or permissions.
- Caching: Store function results to avoid redundant calculations.
- Error Handling: Implement custom error handling mechanisms.
Advantages
- Readability: Promote clear separation of concerns in your code.
- Reusability: Easily apply decorators to different functions.
- Flexibility: Modify function behavior dynamically without complicated subclassing.
- Open/Closed Principle: Extend functionality without directly changing existing code.
Advanced Concepts
- Decorators with Arguments: Decorators can take arguments to customize their behavior further.
- Class Decorators: Decorators can also modify classes.
- Chaining Decorators: Multiple decorators can be stacked on top of a function.