functools.lru_cache是python 3.11中最快、最轻量的函数级缓存方案,线程安全、无需依赖,适用于参数可哈希的纯函数;需避免不可哈希类型,合理设置maxsize和typed,并用cache_info()调试。

用 functools.lru_cache 最快实现函数级缓存
Python 3.11 自带的 lru_cache 就是轻量级 LRU 缓存的首选,它不依赖外部库、无额外内存开销,且线程安全。它只缓存函数调用结果,不缓存任意对象,所以适用场景明确:纯函数、参数可哈希、结果计算开销大。
常见错误是给含不可哈希参数(如 dict、list)的函数加装饰器,会直接抛 TypeError: unhashable type。解决办法只有两个:改用 tuple 等可哈希类型传参,或换手动缓存方案。
实操建议:
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
- 默认不设
maxsize(即maxsize=128)已足够轻量;设为None表示无限制,但需警惕内存泄漏 - 加
typed=True可区分1和1.0,避免意外命中,但有微小性能损耗 - 调试时用
my_func.cache_info()查看命中率和当前大小,比猜更可靠
手动实现对象级缓存用 collections.OrderedDict
当你要缓存非函数结果(比如从 DB 查出的 user 对象),或需要控制键构造逻辑(如忽略某字段)、支持异步、或统一管理多个缓存实例时,OrderedDict 是最简可控的选择。它在 Python 3.11 中仍是标准库中唯一自带的有序映射结构。
容易踩的坑是忘记在访问时调用 move_to_end(key) —— 否则 LRU 顺序不会更新,缓存淘汰就失效了。另外,手动管理需自行处理并发读写,多线程下必须加锁。
实操建议:
- 封装成类时,把
__getitem__和__setitem__都加上move_to_end - 淘汰策略用
popitem(last=False)弹出最久未用项,别用popitem()(它弹最新) - 若键是复合结构(如
(user_id, include_profile)),确保所有元素都可哈希
避免误用 weakref.WeakValueDictionary 当 LRU 缓存
WeakValueDictionary 不是 LRU 缓存替代品,它只保证值不阻止垃圾回收,但完全不维护访问顺序,也不会自动淘汰。有人试图靠它“省内存”,结果发现缓存大小失控、命中率极低,甚至因对象提前被回收导致反复重建。
它的唯一合理用途是:你确信缓存值本身生命周期由外部管理,且你只关心“存在即可用”,不关心频次与顺序。比如缓存大型图像对象,同时确保图像引用在其他地方长期持有。
实操建议:
- 别把它和
OrderedDict混用——弱引用 + 手动排序 = 难以调试的竞态 - 若真要结合弱引用和 LRU,得自己维护一个
OrderedDict存 key →weakref.ref,并定期清理失效引用,复杂度陡增 - Python 3.11 的
weakref.WeakKeyDictionary同理,不解决顺序问题
性能与兼容性关键点:Python 3.11 的 lru_cache 优化
Python 3.11 对 lru_cache 做了底层提速,调用开销比 3.10 降低约 15%–20%,尤其在高频率小参数函数上更明显。但它仍不支持异步函数(async def),也不能缓存返回 None 的函数结果(因为内部用 None 标记未命中)。
另一个易忽略点:lru_cache 是基于函数对象绑定的,同一函数多次装饰会产生独立缓存,无法共享。如果需要跨模块共享缓存,必须确保装饰的是同一个函数对象,而不是分别 import 后再装饰。
实操建议:
- 高频小函数(如解析字符串)优先用
lru_cache(maxsize=1024),别盲目设None - 异步场景只能手动用
OrderedDict+asyncio.Lock,没有银弹 - 测试缓存行为时,别只看是否“不报错”,务必验证
cache_info().hits是否增长
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










