装饰器模式可通过缓存避免递归函数重复计算,显著提升性能;手动实现需用闭包维护字典缓存并确保递归调用装饰后函数,推荐使用functools.lru_cache自动处理哈希、大小限制与线程安全。

装饰器模式可以为递归函数添加缓存能力,避免重复计算,显著提升性能。核心思路是用一个字典(或 lru_cache)记录已计算的参数与结果,在每次调用前查表,命中则直接返回,未命中才执行原函数并缓存结果。
手动实现缓存装饰器
适合理解原理或需要自定义逻辑(如清除策略、日志)。关键点在于闭包保存缓存字典,并确保递归调用也走装饰后的函数。
- 装饰器返回一个新函数,该函数内部维护
cache = {} - 新函数先检查
args(和kwargs,需可哈希)是否在缓存中 - 未命中时调用原始函数(注意:必须调用装饰后的函数本身,而非原函数,否则递归不生效)
- 将结果存入缓存并返回
使用 functools.lru_cache(推荐)
Python 标准库提供开箱即用的方案,自动处理哈希、大小限制和线程安全。
- 直接在递归函数上加
@lru_cache(maxsize=None)即可 -
maxsize控制缓存条目上限,设为None表示无限制 - 要求所有参数可哈希(如不能传列表、字典等不可哈希类型)
- 例如斐波那契:
@lru_cache(None) def fib(n): return n if n
注意事项与常见陷阱
缓存递归函数时容易忽略几个细节,导致失效或错误。
- 装饰器必须作用于函数定义处,不能在调用时临时包装(否则递归调用仍是原函数)
- 若函数有默认参数或关键字参数,
lru_cache默认会区分不同调用方式(如f(1)和f(x=1)视为不同键) - 缓存基于参数值,不感知外部状态变化;若函数依赖全局变量,缓存可能返回过期结果
- 递归深度极大时,缓存本身占用内存,需权衡空间与时间
进阶:支持不可哈希参数的缓存
当参数含列表、字典等不可哈希类型时,需预处理为可哈希形式。
- 对
args和kwargs中的不可哈希对象做深拷贝 + 序列化(如json.dumps或repr) - 注意
repr不总是唯一(如浮点精度、对象 ID),建议用json或pickle(后者需确保安全) - 手动装饰器中可封装此逻辑,
lru_cache本身不支持,需自行实现键生成逻辑











