Python装饰器本质是“函数的函数”,通过闭包在不修改原函数前提下动态附加日志、缓存、权限等横切逻辑,支持单层(无参)、双层(带参)及三层(工厂函数)结构,并需用@functools.wraps保留元信息。

Python装饰器本质是“函数的函数”,核心设计思路是在不修改原函数代码的前提下,动态附加新行为。它利用了Python中函数是一等对象(可赋值、可传参、可返回)的特性,通过闭包封装逻辑,实现运行时的功能增强。
装饰器的三层结构:目标函数 → 包装函数 → 外层工厂(可选)
最简装饰器由两层构成:外层接收被装饰函数,内层(包装函数)执行增强逻辑并调用原函数;若需支持参数化配置(如@retry(max_times=3)),则增加第三层——返回装饰器的工厂函数。
- 单层(无参数装饰器):直接返回包装函数
- 双层(带参数装饰器):外层接收配置参数,返回真正的装饰器(即第二层)
- 包装函数务必使用
@functools.wraps(func)保留原函数的__name__、__doc__等元信息,否则调试和反射会出问题
典型功能增强场景与实现要点
装饰器不是炫技工具,而是为解决重复横切关注点而生。常见用途有日志记录、权限校验、缓存、重试、性能计时等,关键在于把通用逻辑从业务代码中剥离出来。
- 日志类:在包装函数中添加
print(f"Calling {func.__name__}")和异常捕获后的日志输出 - 缓存类(如
@lru_cache):用字典或functools.lru_cache缓存返回值,需考虑参数是否可哈希 - 权限类:在调用前检查当前用户角色,不满足则抛出
PermissionError - 重试类:捕获指定异常,在循环中重试,并支持指数退避和最大次数限制
装饰器链与执行顺序:自下而上,层层包裹
多个装饰器叠加(如@auth @log @cache)时,实际等价于auth(log(cache(func))),即最靠近函数的装饰器最先执行,但其包装逻辑最内层。理解这点对调试和设计嵌套行为至关重要。
立即学习“Python免费学习笔记(深入)”;
- 执行流程:调用
func()→ 进入cache包装 → 进入log包装 → 进入auth包装 → 执行原函数 - 返回流程:原函数返回 → 出
auth→ 出log→ 出cache→ 返回给调用方 - 若某层拦截返回(如权限拒绝),后续包装层不会执行
实战建议:从简单开始,警惕副作用与状态泄漏
初学装饰器易陷入“过度抽象”或“隐式状态”陷阱。推荐按此路径演进:
- 先手写一个无参数装饰器,手动测试包装过程(如
new_func = my_dec(func); new_func()) - 再升级为带参数版本,确认工厂函数返回的是可调用对象
- 避免在闭包中维护可变默认状态(如用
list做缓存),改用函数属性或外部存储 - 异步函数需用
async def定义包装函数,并用await调用原协程,不可混用同步/异步装饰器










