@lru_cache通过缓存已计算结果实现空间换时间,要求函数确定性且参数可哈希;maxsize控制条目数,typed影响类型敏感性;需用cache_info()验证命中率并防范不可哈希参数与副作用。

为什么递归函数加 @lru_cache 能显著提速
因为普通递归(比如斐波那契)会反复计算相同输入,时间复杂度指数级增长;@lru_cache 把已算过的 (args, kwargs) 结果存起来,下次直接返回——本质是用空间换时间,且对纯函数最有效。
关键前提是:函数必须是**确定性的**(相同输入永远返回相同输出),且参数都得是可哈希的(list、dict 这类不行)。
- 不加缓存的
fib(35)可能要算几秒;加了之后几乎瞬时返回 -
@lru_cache默认不限制大小(maxsize=None),但生产环境建议设具体值防内存爆炸 - 如果函数有副作用(比如修改全局变量、写文件),缓存会让行为不可预期——别用
@lru_cache 的参数怎么选:maxsize 和 typed 的实际影响
maxsize 控制缓存条目上限,typed 决定是否区分参数类型(比如 1 和 1.0 算不算同一个键)。
-
maxsize=128是常用折中值:够用又不至于吃光内存;设为1相当于只记最近一次结果(适合某些滑动场景) -
maxsize=0会禁用缓存(但装饰器仍存在,只是不存不查)——可用于临时关闭调试 -
typed=True在混合数值类型时有用(如函数同时接受int和float),但带来额外哈希开销,一般不用 - 缓存大小不是按字节算的,而是按调用组合数;大对象(如长 tuple)本身也会占内存
递归爆栈或缓存失效的典型表现和排查方法
加了 @lru_cache 还慢?或者报 RecursionError?大概率不是缓存没起作用,而是其他地方出了问题。
立即学习“Python免费学习笔记(深入)”;
- 错误现象:
RecursionError: maximum recursion depth exceeded—— 缓存没覆盖到深层递归入口(比如初始调用参数太偏,中间态根本没被复用) - 错误现象:速度没变化 —— 检查参数是否含
list、dict、set等不可哈希类型,会直接绕过缓存并报TypeError - 用
func.cache_info()查真实命中率:Hits低说明缓存利用率差,可能参数组合过于分散 - 用
func.cache_clear()在测试中重置状态,避免前序调用污染结果
一个安全可用的带缓存递归模板(含错误防护)
别直接套用网上裸写的 @lru_cache 斐波那契示例。真实代码要考虑边界和健壮性:
from functools import lru_cache
<p>@lru_cache(maxsize=128)
def safe_fib(n: int) -> int:
if n < 0:
raise ValueError("n must be non-negative")
if n <= 1:
return n
return safe_fib(n - 1) + safe_fib(n - 2)
注意三点:
- 类型提示让 IDE 和检查工具能提前发现传入
str或float的问题 - 显式抛出
ValueError,而不是让负数递归到爆栈 - 缓存大小写死,不依赖默认的
None,避免在资源受限环境失控
缓存真正起效的前提,是你清楚哪些输入会高频重复——盲目加 @lru_cache 可能白费内存还掩盖逻辑缺陷。



















