35
装饰器
装饰器(Decorators):不改源码就增强函数能力
你现在可能会困惑什么
“为什么不直接改函数体,还要套一层?”
当你要给很多函数加相同能力(日志、鉴权、计时)时, 装饰器能减少重复代码并统一规范。
一句话定义
装饰器是接收函数并返回增强函数的高阶函数。
生活类比
像给手机加壳和贴膜: 本体不变,但能力增强。
最小可运行例子
from functools import wraps
def logger(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"[LOG] 调用: {func.__name__}")
return func(*args, **kwargs)
return wrapper
@logger
def greet(name):
return f"Hello, {name}"
print(greet("JR"))
关键理解
@logger等价于greet = logger(greet)wrapper负责“增强行为 + 调原函数”@wraps保留原函数元信息(名称、doc)
课堂小测(5 分钟)
- 写一个打印函数名的装饰器。
- 改成打印函数参数。
- 实现
@timer输出耗时(ms)。
课堂小测参考答案与判分点
- 参考答案方向:能写出可运行代码,并覆盖题目中的核心条件与边界输入。
- 判分点 1(正确性):主流程结果正确,关键分支可执行。
- 判分点 2(可读性):变量命名清晰,结构不过度嵌套。
- 判分点 3(健壮性):对空值、类型错误或异常输入有基础保护。
迁移任务(课后)
把两个重复写日志的函数改造成“一个装饰器 + 两个纯业务函数”。
本节验收标准
你能独立做到:
- 写一个基础装饰器
- 正确处理
*args, **kwargs - 解释装饰器如何替换原函数调用链
常见报错与调试步骤(新手版)
- 报错看不懂:先读最后一行错误类型(如
TypeError、NameError),再回到对应代码行定位。 - 不确定变量值:在关键位置临时
print(变量, type(变量)),先确认数据是否符合预期。 - 改了代码却没生效:确认文件已保存、运行的是当前文件、终端环境(venv)是否正确。
常见误区
-
误区:忘记
return wrapper。 -
正解:不返回就不会完成替换。
-
误区:不写
*args, **kwargs导致参数丢失。 -
正解:通用装饰器必须透传参数。