一、从咖啡店点单理解装饰器本质
想象这样一个场景:你走进咖啡店点了一杯美式咖啡,但可以随时添加各种配料:
def americano():
"""基础咖啡"""
return "美式咖啡"
# 装饰器函数
def add_milk(func):
def wrapper():
return func() + "+鲜奶"
return wrapper
# 装饰器语法糖
@add_milk
def coffee():
return americano()
print(coffee()) # 输出:美式咖啡+鲜奶
二、新手必踩的三大装饰器陷阱
2.1 元信息丢失之谜
直接使用装饰器会导致函数文档丢失:
print(coffee.__name__) # 输出:wrapper
print(coffee.__doc__) # 输出:None
解决方案:
from functools import wraps
def add_sugar(func):
@wraps(func) # 关键修复
def wrapper():
return func() + "+砂糖"
return wrapper
2.2 多层装饰器的执行顺序
装饰器的应用顺序像洋葱包裹:
@add_milk
@add_sugar
def special_coffee():
return americano()
# 等价于 add_milk(add_sugar(special_coffee))
print(special_coffee()) # 美式咖啡+砂糖+鲜奶
2.3 带参数装饰器的正确姿势
实现可配置的装饰器:
def repeat(num_times):
# 外层处理装饰器参数
def decorator(func):
# 内层处理函数参数
@wraps(func)
def wrapper(*args, **kwargs):
results = []
for _ in range(num_times):
results.append(func(*args, **kwargs))
return results
return wrapper
return decorator
@repeat(3)
def greet(name):
return f"Hello {name}"
print(greet