流畅的Python - 第九章 函数装饰器和闭包
闭包是装饰器的基础:缓存字典通过闭包保留,实现了装饰器的状态管理(无需全局变量); 装饰器是高阶函数:以 “无侵入” 的方式给函数添加缓存功能,原函数(如 fibonacci)无需修改一行代码; 解决元数据丢失陷阱:通过 @wraps(func) 保留原函数的标识和文档; 聚焦横切关注点:缓存是 “通用功能”,用装饰器实现后,可复用在任何需要性能优化的函数上(如斐波那契、耗时计算),避免重复代码。
第九章的核心主题是:通过闭包实现装饰器,以无侵入式的方式为函数添加通用功能,同时解决使用过程中的常见陷阱。
主要有以下几个核心要点:
-
闭包是装饰器的基础
闭包并非简单的函数嵌套,而是能保留外部函数作用域变量绑定的嵌套内部函数—— 即使外部函数执行完毕,内部函数依然可以访问和修改这些变量(需借助
nonlocal关键字解决变量重新绑定问题)。章节明确区分了 “嵌套函数” 和 “闭包” 的差异:只有当内部函数引用了外部函数的变量,且被返回并在外部函数作用域外执行时,才构成闭包。
-
装饰器的本质是高阶函数
装饰器的核心逻辑是接收一个函数作为参数,返回一个新函数,新函数会在原函数的执行前后添加额外逻辑(如日志记录、性能监控、缓存、权限校验等),同时保持原函数的调用方式不变。
这一特性完美契合 “开放 - 封闭原则”—— 对扩展功能开放,对修改原函数代码封闭。
-
解决装饰器的核心陷阱:元数据丢失
直接实现的装饰器会导致原函数的元数据(如
__name__、__doc__、__module__)被覆盖,使得函数的身份标识和文档字符串失效。章节给出标准解决方案:使用
functools.wraps装饰器包装装饰器的返回函数,保留原函数的元数据,保证装饰器的透明性。 -
进阶装饰器的实现逻辑
- 带参数的装饰器:本质是三层嵌套函数—— 最外层函数接收装饰器参数,中间层函数接收被装饰函数,最内层函数实现增强逻辑。
- 装饰器叠加:多个装饰器装饰同一个函数时,靠近函数的装饰器先执行(自底向上应用,自顶向下执行)。
- 类装饰器:通过实现
__call__方法的类来构建装饰器,适合需要维护状态(如计数、缓存)的场景,相比闭包更易管理复杂状态。
-
装饰器的适用场景:聚焦横切关注点
装饰器最适合实现横切关注点—— 即与业务逻辑无关、但多个函数都需要的通用功能(如日志、缓存、事务管理、参数校验等),避免在不同函数中重复编写相同代码