Advanced Decorator Patterns
Class Decorators
Class decorators provide a way to modify or enhance entire classes dynamically.
def singleton(cls):
instances = {}
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class DatabaseConnection:
def __init__(self):
self.connection = "Active"
Decorator Chaining
graph LR
A[Original Function] --> B[Decorator 1]
B --> C[Decorator 2]
C --> D[Final Decorated Function]
def bold(func):
def wrapper():
return f"<b>{func()}</b>"
return wrapper
def italic(func):
def wrapper():
return f"<i>{func()}</i>"
return wrapper
@bold
@italic
def greet():
return "Hello, LabEx!"
Parametrized Decorators
Decorator Type |
Description |
Complexity |
Simple |
No arguments |
Low |
Parametrized |
Accepts configuration |
Medium |
Class-based |
Uses class structure |
High |
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(times=3)
def display_message():
print("LabEx Learning Platform")
Contextual Decorators
def authenticated(role):
def decorator(func):
def wrapper(*args, **kwargs):
user_role = get_current_user_role()
if user_role == role:
return func(*args, **kwargs)
else:
raise PermissionError("Unauthorized access")
return wrapper
return decorator
@authenticated(role='admin')
def delete_user(user_id):
## Deletion logic
pass
Memoization Decorator
def memoize(func):
cache = {}
def wrapper(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
return wrapper
@memoize
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
import time
import functools
def performance_tracker(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} executed in {end_time - start_time} seconds")
return result
return wrapper
Advanced Patterns
- Decorator Factories
- Meta-programming
- Aspect-Oriented Programming
- Runtime Code Modification
Best Practices
- Keep decorators focused
- Minimize performance overhead
- Use
functools.wraps
- Handle edge cases
- Document decorator behavior
Error Handling in Decorators
def error_handler(func):
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"Error in {func.__name__}: {e}")
## Optionally log or handle the error
return wrapper
By mastering these advanced decorator patterns, you can create powerful, flexible, and maintainable Python code that leverages the full potential of decorators.