Python 装饰器堆叠
多个装饰器可以同时应用到一个函数上,形成装饰器堆叠。
基本语法
Python
@decorator1
@decorator2
@decorator3
def func():
pass
# 等价于
func = decorator1(decorator2(decorator3(func)))
执行顺序
应用顺序(从下到上)
装饰器按从下到上的顺序应用:
Python
def decorator_a(func):
print("A 应用")
def wrapper(*args, **kwargs):
print("A 执行前")
result = func(*args, **kwargs)
print("A 执行后")
return result
return wrapper
def decorator_b(func):
print("B 应用")
def wrapper(*args, **kwargs):
print("B 执行前")
result = func(*args, **kwargs)
print("B 执行后")
return result
return wrapper
@decorator_a
@decorator_b
def greet(name):
print(f"Hello, {name}!")
# 输出:
# B 应用
# A 应用
执行顺序(从外到内)
调用时,最外层装饰器先执行:
Python
greet("World")
# 输出:
# A 执行前
# B 执行前
# Hello, World!
# B 执行后
# A 执行后
执行流程图
Python
应用阶段(定义时):
func → decorator_b(func) → wrapper_b
wrapper_b → decorator_a(wrapper_b) → wrapper_a
执行阶段(调用时):
wrapper_a() → print("A 执行前")
→ wrapper_b() → print("B 执行前")
→ func() → print("Hello")
→ print("B 执行后")
→ print("A 执行后")
实际应用场景
日志 + 计时
Python
import time
from functools import wraps
def log(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"调用: {func.__name__}")
return func(*args, **kwargs)
return wrapper
def timer(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
print(f"耗时: {time.perf_counter() - start:.4f}s")
return result
return wrapper
@log
@timer
def process_data(n):
"处理数据"
time.sleep(n)
return n * 2
process_data(0.1)
# 调用: process_data
# 耗时: 0.1005s
缓存 + 验证
Python
def cache(func):
"简单缓存装饰器"
cached = {}
@wraps(func)
def wrapper(*args):
if args not in cached:
cached[args] = func(*args)
return cached[args]
return wrapper
def validate(func):
"参数验证装饰器"
@wraps(func)
def wrapper(*args):
if any(arg < 0 for arg in args):
raise ValueError("参数不能为负数")
return func(*args)
return wrapper
@cache
@validate
def multiply(a, b):
return a * b
multiply(3, 4) # 12,计算并缓存
multiply(3, 4) # 12,从缓存读取
multiply(-1, 2) # ValueError
重试 + 异常处理
Python
def retry(attempts=3):
"重试装饰器"
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for i in range(attempts):
try:
return func(*args, **kwargs)
except Exception as e:
if i == attempts - 1:
raise
print(f"重试 {i + 1}/{attempts}")
return wrapper
return decorator
def handle_errors(default=None):
"异常处理装饰器"
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"错误: {e}")
return default
return wrapper
return decorator
@handle_errors(default="failed")
@retry(attempts=2)
def risky_operation(data):
if data < 0:
raise ValueError("负数错误")
return data * 10
risky_operation(5) # 50
risky_operation(-1) # 重试后返回 "failed"
堆叠顺序的影响
不同顺序产生不同效果:
text
# 顺序A:先验证后缓存
@cache
@validate
def func(x):
return x * 2
# 顺序B:先缓存后验证
@validate
@cache
def func(x):
return x * 2
| 顺序 | 效果 |
|---|---|
| 先 validate 后 cache | 验证通过才缓存,缓存数据可靠 |
| 先 cache 后 validate | 可能缓存无效数据 |
要点总结
| 规则 | 说明 |
|---|---|
| 应用顺序 | 从下到上,最下面的装饰器最先应用 |
| 执行顺序 | 从外到内,最外层装饰器最先执行 |
| 等价形式 | @a @b def f() 等于 f = a(b(f)) |
| 设计原则 | 根据功能依赖关系决定顺序 |
装饰器堆叠顺序至关重要:应用时从下到上,执行时从外到内,类似洋葱结构。
D:\git2\jwdev\articles\PYTHON\进阶\装饰器深入\装饰器堆叠.md
📝 发现内容有误?点击此处直接编辑