Python装饰器进阶:5个实际场景中的高级用法详解
一、装饰器基础回顾
装饰器是Python中修改函数或类的行为的特殊语法,使用@符号表示。基础装饰器结构如下:
def simple_decorator(func):
def wrapper(*args, **kwargs):
print("函数执行前操作")
result = func(*args, **kwargs)
print("函数执行后操作")
return result
return wrapper
@simple_decorator
def example_function():
print("核心功能执行")
二、带参数的装饰器
实际开发中,我们经常需要配置装饰器的行为:
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
print(f"尝试 {attempts}/{max_attempts} 失败,{delay}秒后重试")
time.sleep(delay)
raise RuntimeError("所有重试尝试失败")
return wrapper
return decorator
@retry(max_attempts=5, delay=2)
def fetch_data():
# 模拟可能失败的API请求
import random
if random.random() < 0.7:
raise ConnectionError("API请求失败")
return "数据获取成功"
三、类装饰器的实用场景
装饰器不仅可以修饰函数,还能修饰整个类:
def singleton(cls):
instances = {}
def wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return wrapper
@singleton
class DatabaseConnection:
def __init__(self):
print("建立数据库连接")
def query(self, sql):
print(f"执行查询: {sql}")
# 测试单例模式
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2) # 输出: True
四、装饰器堆叠与执行顺序
多个装饰器可以叠加使用,执行顺序从下往上:
def decorator1(func):
def wrapper():
print("装饰器1 - 前")
func()
print("装饰器1 - 后")
return wrapper
def decorator2(func):
def wrapper():
print("装饰器2 - 前")
func()
print("装饰器2 - 后")
return wrapper
@decorator1
@decorator2
def combined_example():
print("核心功能")
combined_example()
# 输出顺序:
# 装饰器1 - 前
# 装饰器2 - 前
# 核心功能
# 装饰器2 - 后
# 装饰器1 - 后
五、性能分析装饰器实战
开发中常用的性能分析工具:
import time
from functools import wraps
def profile(func):
@wraps(func) # 保留原函数元信息
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - start
print(f"{func.__name__} 执行耗时: {elapsed:.6f}秒")
return result
return wrapper
@profile
def calculate_factorial(n):
result = 1
for i in range(1, n+1):
result *= i
return result
calculate_factorial(10000)
六、总结与最佳实践
- 使用
functools.wraps
保留函数元信息 - 装饰器适合实现横切关注点(日志、权限、缓存等)
- 避免过度使用装饰器导致代码可读性下降
- 考虑使用类装饰器处理复杂状态管理