用lru_cache前必须确认函数是纯函数,否则缓存结果会错误;常见问题包括依赖外部状态、可变参数、不可哈希类型及缓存不自动失效。

直接说结论:用 lru_cache 前先确认函数是否「纯」,否则缓存结果会错得悄无声息。
为什么加了 @lru_cache 却没提速?
常见原因是函数依赖外部状态(比如全局变量、类实例属性、文件读取、time.time()),缓存的是第一次调用的结果,后续调用直接返回旧值——表面快了,实际逻辑已错。
- 检查函数是否只依赖参数输入,不读写外部可变对象
- 避免在被装饰函数里修改
list、dict等可变默认参数 - 如果必须用外部数据,改用带版本号的 key(例如
@lru_cache(maxsize=128)+ 手动拼入data_version参数)
maxsize 设多少才合理?
设为 None 表示无限制,但内存可能持续增长;设为 128(默认值)适合多数小参数场景;设为 0 会禁用缓存(仅用于调试时对比性能)。
- 参数是大型对象(如
numpy.ndarray或长字符串)时,即使maxsize=1也可能吃掉几百 MB 内存 - 用
cache_info()查看命中率:my_func.cache_info().hits / (my_func.cache_info().misses + my_func.cache_info().hits) - 命中率低于 20% 时,缓存收益极低,不如关掉
遇到 TypeError: unhashable type 怎么办?
lru_cache 要求所有参数可哈希,所以传入 list、dict、set 会直接报错。
立即学习“Python免费学习笔记(深入)”;
- 快速修复:把可变参数转成
tuple(list→tuple(lst))或frozenset(set→frozenset(s)) - 更稳妥做法:在函数内部做转换,对外接口保持原样,例如
def f(data: list): return _f(tuple(data)),再对_f加装饰器 - 自定义对象要支持缓存,需实现
__hash__和__eq__,且确保实例不可变
最常被忽略的一点:缓存不自动失效。函数逻辑变了、依赖的数据更新了、甚至只是升级了 Python 版本导致哈希值变化,lru_cache 都不会感知——它只认参数的哈希值,别的都不管。



















