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 |
是否区分参数类型(3 与 3.0 分开缓存) |
重载语义或类型敏感时设 True |
无参 @lru_cache:等价 @lru_cache(maxsize=128)。
functools.cache(3.9+):等价 @lru_cache(maxsize=None),API 无参数,语义更简单。
3. 最小可运行示例
1 | from functools import lru_cache |
1 | 832040 |
带 maxsize 与 typed:
1 |
|
4. 常见变体
手动清缓存
1 | fib.cache_clear() |
查看缓存内容(调试)
1 | print(fib.cache_parameters()) # maxsize, typed |
3.9+ 无限缓存
1 | from functools import cache |
不可哈希参数:lru_cache 要求参数可哈希。列表/字典作参需转 tuple/frozenset,或改用自定义缓存键:
1 |
|
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 缓存 |
键非参数元组、需精细失效逻辑 |