加了 @lru_cache 却没缓存淘汰是因为默认 maxsize=none,即无限缓存;只有设为正整数(如128)才启用lru淘汰机制,基于双向链表+哈希表实现。

直接用 functools.lru_cache 就能实现标准 LRU 淘汰,但默认不淘汰(即无限缓存),必须显式设 maxsize 才真正启用 LRU 行为。
为什么加了 @lru_cache 却没看到缓存淘汰?
因为 lru_cache(maxsize=None) 是默认行为,等价于“无容量限制”,内部用的是字典而非带顺序的链表,根本不会触发淘汰逻辑。只有当 maxsize 设为正整数(如 128)或 128 时,才启用基于访问顺序的双向链表 + 哈希表组合结构,此时才会按 LRU 规则踢出最久未用项。
-
maxsize=128:缓存最多存 128 个不同参数组合的结果,超限后自动淘汰最久未调用的那一个 -
maxsize=1:相当于“只记最后一次调用结果”,适合状态简单、参数固定场景 -
maxsize=None或省略参数:缓存全量,不淘汰,内存可能持续增长
lru_cache 的键是怎么生成的?哪些参数会影响缓存命中?
缓存键由函数所有位置参数和关键字参数的值共同决定,且要求参数可哈希(hashable)。常见踩坑点:
- 传入
list、dict、set等不可哈希类型会直接抛TypeError: unhashable type - 传入
numpy.ndarray或自定义对象,若没实现__hash__同样失败 - 关键字参数顺序不影响键(
f(a=1, b=2)和f(b=2, a=1)视为同一键),但参数名必须一致 - 如果函数接受
*args或**kwargs,它们会被展开参与键计算;含可变参数的函数慎用lru_cache
如何查看/控制当前缓存状态?
lru_cache 返回的装饰后函数自带两个方法:cache_info() 和 cache_clear(),是调试和运维的关键入口:
-
cache_info()返回命名元组,字段包括hits、misses、maxsize、currsize—— 注意currsize是当前实际缓存条目数,不是“已用/总容量”百分比 - 频繁调用后发现
currsize == maxsize但hits极低,说明参数组合高度分散(比如含时间戳、UUID),缓存效率差 -
cache_clear()会清空整个缓存,适合配置变更、数据重载等场景;它不区分 key,是全局操作
示例:
@lru_cache(maxsize=3)
def fib(n):
return n if n print(fib.cache_info()) # CacheInfo(hits=0, misses=1, maxsize=3, currsize=1)
fib(10)
print(fib.cache_info()) # hits 增长,currsize 不会超 3
真正用起来要盯住 currsize 和 hits/misses 比值;LRU 是否生效不看装饰器有没有写,而看 maxsize 是否设为有限值,以及参数是否稳定可哈希。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











