@lru_cache失效主因有四:一是参数不可哈希(如list/dict)导致缓存完全不启用;二是可变默认参数破坏键一致性;三是直接装饰实例方法因self不可哈希而无效;四是LRU容量淘汰或手动清空。
Python函数缓存(如 @lru_cache)失效,通常不是缓存“坏了”,而是调用方式或参数特性触发了缓存机制的限制条件。理解这些限制,才能避免误以为缓存没生效。
@lru_cache 要求所有位置参数和关键字参数都必须是可哈希的(hashable)。一旦传入 list、dict、set 或自定义的不可哈希对象,缓存会直接跳过,每次调用都重新执行函数,且不报错——这是最隐蔽的失效原因。
my_func([1, 2], key={'a': 1}) → 缓存不记录任何条目(1, 2)),用 types.MappingProxyType(dict) 或 frozenset 代替 dict/set;或在函数内部做标准化转换(如 tuple(sorted(kwargs.items())))my_func.cache_info(),若 hits=0 且 currsize=0,大概率是参数不可哈希带默认值的参数(尤其是可变默认参数)容易造成逻辑混淆。例如:
from functools import lru_cache@lru_cache() def load_confi
g(config_dict={}): # 危险!{} 是可变默认参数 return config_dict.copy()
第一次调用 load_config() 后,config_dict 实际指向同一个字典对象;后续修改该字典会影响缓存键的“内容一致性”,但缓存键仍基于初始 id 或引用,导致结果与预期不符。
None,函数内初始化:config_dict = config_dict or {}
def load_config(config_dict=None): config_dict = {} if config_dict is None else config_dict
@lru_cache 不能直接用于实例方法(self 是不可哈希的),否则每次调用都会因 self 不同而生成新缓存项,形同未缓存。
@lru_cache 的方法,即使参数相同,cache_info().currsize 持续增长@lru_cache + @staticmethod,但需确保所有输入可哈希且不含实例状态cached-property(适合属性级缓存)或 methodtools
@lru_cache(maxsize=N) 在达到容量上限时会按 LRU 策略清除旧项;而 maxsize=None 虽无数量限制,但内存占用可能随调用增长。此外,Python 进程重启、模块重载、或显式调用 cache_clear() 都会导致缓存清空。
func.cache_info(),关注 maxsize、currsize 和 misses 变化趋势lru_cache 做过期管理,改用 functools.cached_property(单次)、或结合 time.time() 自建带 TTL 的缓存封装lru_cache 是线程安全的,但高并发可能导致缓存项被频繁挤出,可适当增大 maxsize 或改用线程局部缓存缓存不是银弹,而是需要匹配使用场景的工具。看清参数本质、避开实例绑定陷阱、合理设置容量边界,才能让 @lru_cache 真正发挥作用。