In Python, decorators are a powerful tool that allows you to modify or extend the behavior of functions or classes without changing their actual code. Decorators are widely used in Python frameworks for tasks such as logging, access control, and caching.
1. What is a Python Decorator?
A decorator is a function that takes another function as an argument, adds some functionality to it, and returns the modified function. Decorators are often used to wrap another function in order to modify its behavior.
Basic Syntax of a Decorator:
def decorator_function(original_function): def wrapper_function(*args, **kwargs): # Add functionality before the original function print(f"Wrapper executed before {original_function.__name__}") result = original_function(*args, **kwargs) # Add functionality after the original function print(f"Wrapper executed after {original_function.__name__}") return result return wrapper_function
2. Creating and Using a Decorator
Example:
def my_decorator(func): def wrapper(): print("Something is happening before the function is called.") func() print("Something is happening after the function is called.") return wrapper @my_decorator def say_hello(): print("Hello!") # Call the decorated function say_hello()
In this example, my_decorator
adds extra functionality before and after the say_hello
function.
3. Using Decorators with Arguments
You can also create decorators that accept arguments.
Example:
def repeat(n): def decorator(func): def wrapper(*args, **kwargs): for _ in range(n): func(*args, **kwargs) return wrapper return decorator @repeat(3) def greet(): print("Hello!") # This will print "Hello!" three times greet()
4. Practical Use Cases for Decorators
- Logging: Automatically log function calls.
- Authorization: Restrict access to certain parts of the code.
- Caching: Store function results for faster access.
- Timing: Measure the execution time of functions.
Example: Logging Decorator
def log_decorator(func): def wrapper(*args, **kwargs): print(f"Function '{func.__name__}' is called with arguments {args} and {kwargs}") return func(*args, **kwargs) return wrapper @log_decorator def add(a, b): return a + b # Call the decorated function result = add(3, 5) print(f"Result: {result}")
5. Class-Based Decorators
Decorators can also be implemented using classes by defining the __call__
method.
Example:
class MyDecorator: def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): print("Class-based decorator: Before the function call.") result = self.func(*args, **kwargs) print("Class-based decorator: After the function call.") return result @MyDecorator def greet(name): print(f"Hello, {name}!") greet("Alice")
6. Chaining Multiple Decorators
You can apply multiple decorators to a single function. They are applied from bottom to top.
Example:
def decorator_one(func): def wrapper(*args, **kwargs): print("Decorator One") return func(*args, **kwargs) return wrapper def decorator_two(func): def wrapper(*args, **kwargs): print("Decorator Two") return func(*args, **kwargs) return wrapper @decorator_one @decorator_two def say_hello(): print("Hello!") say_hello()
In this example, decorator_two
is applied first, followed by decorator_one
.
Conclusion
Python decorators are a powerful tool for modifying and extending the behavior of functions. They help keep your code clean and reusable. Whether you’re adding logging, handling access control, or measuring performance, decorators provide an elegant solution.