装饰器 · lru_cache

0. 一句话定位

维度 内容
作用对象 函数
使用场景 缓存
来源 标准库 functools.lru_cache(3.2+);functools.cache(3.9+,无限缓存)
语法形式 @lru_cache / @lru_cache(maxsize=128, typed=False)

段末注释:LRU(Least Recently Used,LRU) 在缓存满时淘汰最久未使用的条目。

1. 做什么

对被装饰函数,以参数元组为键缓存返回值;相同参数再次调用时直接返回缓存,跳过函数体。适用于纯函数、重复调用且计算成本高的场景。

2. 重点参数

参数 类型 默认值 作用 配置建议
maxsize int / None 128 最多缓存条目数;None 等价无限 内存敏感时设上限;已知键空间有限可设精确值
typed bool False 是否区分参数类型(33.0 分开缓存) 重载语义或类型敏感时设 True

无参 @lru_cache:等价 @lru_cache(maxsize=128)

functools.cache(3.9+):等价 @lru_cache(maxsize=None),API 无参数,语义更简单。

3. 最小可运行示例

1
2
3
4
5
6
7
8
9
10
from functools import lru_cache

@lru_cache(maxsize=None)
def fib(n):
if n < 2:
return n
return fib(n - 1) + fib(n - 2)

print(fib(30)) # 832040
print(fib.cache_info())
1
2
832040
CacheInfo(hits=28, misses=31, maxsize=None, currsize=31)

maxsizetyped

1
2
3
4
5
6
7
8
9
@lru_cache(maxsize=2, typed=True)
def add(a, b):
print("computing")
return a + b

add(1, 2)
add(1, 2) # 命中,无 printing
add(1.0, 2.0) # typed=True,与 (1,2) 不同键
print(add.cache_info())

4. 常见变体

手动清缓存

1
fib.cache_clear()

查看缓存内容(调试)

1
2
print(fib.cache_parameters())  # maxsize, typed
# fib.__wrapped__ 访问原函数

3.9+ 无限缓存

1
2
3
4
5
6
from functools import cache

@cache
def load_config(path):
with open(path) as f:
return f.read()

不可哈希参数lru_cache 要求参数可哈希。列表/字典作参需转 tuple/frozenset,或改用自定义缓存键:

1
2
3
4
@lru_cache(maxsize=128)
def query(sql: str, params_tuple: tuple):
...
# 调用:query("SELECT ...", tuple(params_dict.items()))

5. 适用 / 不适用

适用

  • 纯函数:相同输入恒得相同输出,无副作用
  • 递归、树/图 DP、重复子问题(如 Fibonacci、路径计数)
  • 读取配置、解析不变文件等 I/O 可缓存场景(注意失效策略)

不适用

  • 依赖可变全局状态、随机数、时间的函数
  • 参数不可哈希且无法规范化
  • 返回值极大对象导致内存暴涨(需控制 maxsize
  • 需要按 TTL 过期 → 用 cachetools.TTLCache

6. 易踩坑

  • 实例方法@lru_cache 装饰方法时,self 进入缓存键,不同实例无法共享;类级纯计算宜用 @staticmethod + lru_cache,或模块级函数
  • 可变默认参数与缓存无关,但函数内修改外部状态会使缓存结果「过期」却不会被感知
  • maxsize=128 默认:超过后 LRU 淘汰,命中率下降属正常
  • 线程安全:lru_cache 内部有锁,多线程读缓存安全;仍须保证被包装函数本身线程安全
  • 不要用 lru_cache 缓存带 不可 pickle 对象若后续需多进程

7. 近邻替代

替代 何时用
functools.cache 3.9+、需要无限缓存、API 更简单
functools.cached_property 实例属性首次访问后缓存
cachetools.lru_cache / TTLCache 需 TTL、自定义权重
手动 dict 缓存 键非参数元组、需精细失效逻辑

8. 参考

-------------本文结束感谢您的阅读-------------