Real-world Applications
import time
import functools
def performance_monitor(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} execution time: {end_time - start_time} seconds")
return result
return wrapper
@performance_monitor
def complex_calculation(n):
return sum(range(n))
complex_calculation(1000000)
Authentication and Authorization Decorator
def require_auth(roles):
def decorator(func):
@functools.wraps(func)
def wrapper(user, *args, **kwargs):
if user.role in roles:
return func(user, *args, **kwargs)
raise PermissionError("Unauthorized access")
return wrapper
return decorator
class User:
def __init__(self, name, role):
self.name = name
self.role = role
@require_auth(['admin', 'manager'])
def delete_user(user, user_id):
print(f"User {user_id} deleted by {user.name}")
admin = User("Alice", "admin")
delete_user(admin, 123)
Caching Decorator with Expiration
from functools import wraps
import time
def cache_with_expiry(expiry_seconds):
def decorator(func):
cache = {}
def wrapper(*args, **kwargs):
key = str(args) + str(kwargs)
current_time = time.time()
if key in cache:
result, timestamp = cache[key]
if current_time - timestamp < expiry_seconds:
return result
result = func(*args, **kwargs)
cache[key] = (result, current_time)
return result
return wrapper
return decorator
@cache_with_expiry(expiry_seconds=5)
def expensive_computation(x, y):
time.sleep(2)
return x + y
Decorator Application Scenarios
Scenario |
Decorator Purpose |
Key Benefits |
Logging |
Track function calls |
Audit trails |
Retry Mechanism |
Handle transient failures |
Resilience |
Input Validation |
Ensure data integrity |
Error prevention |
Rate Limiting |
Control API usage |
Resource management |
Retry Mechanism Decorator
def retry(max_attempts=3, delay=1):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
attempts = 0
while attempts < max_attempts:
try:
return func(*args, **kwargs)
except Exception as e:
attempts += 1
if attempts == max_attempts:
raise
time.sleep(delay)
return wrapper
return decorator
@retry(max_attempts=3, delay=2)
def unreliable_network_call():
## Simulated network request
import random
if random.random() < 0.7:
raise ConnectionError("Network error")
return "Success"
Decorator Workflow
graph LR
A[Function Call] --> B{Decorator Check}
B --> |Pass| C[Original Function]
B --> |Fail| D[Error Handling]
C --> E[Return Result]
D --> F[Alternative Action]
Advanced Logging Decorator
import logging
import functools
def log_calls(log_level=logging.INFO):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
logging.log(log_level, f"Calling {func.__name__}")
try:
result = func(*args, **kwargs)
logging.log(log_level, f"{func.__name__} completed successfully")
return result
except Exception as e:
logging.error(f"{func.__name__} raised {type(e).__name__}: {e}")
raise
return wrapper
return decorator
@log_calls(log_level=logging.DEBUG)
def process_data(data):
## Data processing logic
pass
By exploring these real-world applications, developers can leverage decorators to create more robust, maintainable code with LabEx's advanced programming techniques.