Python 装饰器高级应用与实战技巧
装饰器是 Python 中最优雅的语法特性之一,它允许我们在不修改原始函数代码的情况下,为函数添加额外的功能。本文将从实际应用场景出发,深入探讨装饰器的高级用法。
基础回顾
装饰器的本质是一个接受函数作为参数,并返回一个新函数的高阶函数。最简单的装饰器可以这样写:
def timer(func):
import time
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} 执行时间: {end - start:.4f}秒")
return result
return wrapper
@timer
def slow_function():
import time
time.sleep(0.5)
return "完成"
带参数的装饰器
当装饰器需要接受自定义参数时,我们需要再包裹一层函数:
def retry(max_attempts=3, delay=1):
def decorator(func):
import time
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
print(f"第 {attempts} 次失败,{delay} 秒后重试...")
time.sleep(delay)
return wrapper
return decorator
@retry(max_attempts=2, delay=0.5)
def unstable_api():
import random
if random.random() > 0.7:
raise Exception("API 暂时不可用")
return "API 响应成功"
类装饰器
使用类作为装饰器可以更好地维护状态:
class CacheDecorator:
def __init__(self, max_size=100):
self.cache = {}
self.max_size = max_size
self.access_order = []
def __call__(self, func):
def wrapper(*args, **kwargs):
# 创建缓存键
key = (args, frozenset(kwargs.items()))
if key in self.cache:
return self.cache[key]
result = func(*args, **kwargs)
# 更新缓存
if len(self.cache) >= self.max_size:
oldest = self.access_order.pop(0)
del self.cache[oldest]
self.cache[key] = result
self.access_order.append(key)
return result
return wrapper
@CacheDecorator(max_size=50)
def expensive_calculation(n):
print(f"计算 {n} 的斐波那契数...")
if n <= 1:
return n
return expensive_calculation(n-1) + expensive_calculation(n-2)
装饰器堆叠
多个装饰器可以堆叠使用,执行顺序从内到外:
def log_call(func):
def wrapper(*args, **kwargs):
print(f"调用 {func.__name__}({args})")
return func(*args, **kwargs)
return wrapper
def validate_types(*type_args):
def decorator(func):
def wrapper(*args, **kwargs):
for i, (arg, expected_type) in enumerate(zip(args, type_args)):
if not isinstance(arg, expected_type):
raise TypeError(f"参数 {i} 应该是 {expected_type}")
return func(*args, **kwargs)
return wrapper
return decorator
@log_call
@validate_types(int, int)
def add_numbers(a, b):
return a + b
保留原函数元数据
使用 functools.wraps 可以保留原函数的元信息:
import functools
def admin_required(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# 检查权限逻辑
print("检查管理员权限...")
return func(*args, **kwargs)
return wrapper
@admin_required
def delete_user(user_id):
"""删除指定用户"""
return f"用户 {user_id} 已删除"
# 现在 delete_user.__name__ 和 __doc__ 都能正确获取
实战应用:权限控制装饰器
from functools import wraps
class PermissionDenied(Exception):
pass
def require_permission(permissions):
"""权限检查装饰器"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
user = kwargs.get('user')
if not user or not any(p in user.get('permissions', []) for p in permissions):
raise PermissionDenied(f"需要权限: {permissions}")
return func(*args, **kwargs)
return wrapper
return decorator
# 使用示例
class UserService:
@require_permission(['user:read'])
def get_user(self, user_id, user):
return {"id": user_id, "name": "测试用户"}
@require_permission(['user:write'])
def update_user(self, user_id, data, user):
return {"id": user_id, **data}
实战应用:性能监控装饰器
import time
import functools
from collections import defaultdict
class PerformanceMonitor:
def __init__(self):
self.stats = defaultdict(list)
def track(self, func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
end = time.perf_counter()
duration = end - start
self.stats[func.__name__].append(duration)
return result
return wrapper
def get_stats(self):
report = {}
for func_name, times in self.stats.items():
report[func_name] = {
'total_calls': len(times),
'avg_time': sum(times) / len(times),
'max_time': max(times),
'min_time': min(times)
}
return report
# 使用示例
monitor = PerformanceMonitor()
@monitor.track
def process_data(n):
import random
time.sleep(random.uniform(0.01, 0.1))
return n * 2
总结
装饰器是 Python 中强大的代码复用工具。通过合理使用装饰器,我们可以:
1. 保持代码简洁和可维护性
2. 实现横切关注点(日志、缓存、权限等)
3. 提高代码的可读性和复用性
在实际项目中,建议将常用装饰器整理到单独的模块中,并配合 functools.wraps 使用,以保持良好的代码质量。
