Python @lru_cache LRU缓存装饰器 作者:马育民 • 2026-05-29 18:53 • 阅读:10000 # 介绍 `lru_cache` 是 Python **functools** 模块提供的 **装饰器**,实现 **[最近最少使用(LRU)缓存](https://www.malaoshi.top/show_1EF5nwVYkx07.html "最近最少使用(LRU)缓存")**,用来缓存函数返回结果,避免重复计算,大幅 **提升 重复调用的执行效率**。 # 基本概念 - **LRU**:Least Recently Used,最近最少使用。缓存满时,自动淘汰**最久没被调用**的结果。详见 [链接](https://www.malaoshi.top/show_1EF5nwVYkx07.html "链接") - 作用:**相同入参 → 直接返回缓存结果,不再执行函数体**。 - 位置:`from functools import lru_cache` --- # 基础用法 ### 1. 最简使用 ```python from functools import lru_cache @lru_cache def add(a, b): print("执行计算") return a + b add(1, 2) # 执行计算 → 返回3 add(1, 2) # 直接读缓存,不打印 add(2, 3) # 新参数,重新执行 ``` ### 2. 设置缓存最大容量 `maxsize` 参数:限制缓存条目数量 - 不传值:缓存数量最多 **128**,达到 128 条后,触**发 LRU 淘汰规则**,移除最久未使用的数据 - `maxsize=数字`:最多缓存 N 条,满了自动 LRU 淘汰 - `maxsize=None`(默认):**无上限缓存、关闭淘汰** ```python @lru_cache(maxsize=3) # 最多存3条结果 def func(x): return x * 2 ``` ### 3. `typed` 参数(区分参数类型) - `typed=False`(默认):**不区分类型**,`1` 和 `1.0` 视为同一个参数 - `typed=True`:区分类型,`int(1)` 和 `float(1.0)` 算不同入参 ```python @lru_cache(typed=True) def show(x): return type(x) show(1) show(1.0) # 重新执行,不会命中缓存 ``` --- # 限制 ### 1. 函数参数必须是**可哈希类型** 可哈希:`int/float/str/tuple/frozenset/None` **不可哈希不能缓存**:`list/dict/set` ❌ 错误示例: ```python @lru_cache def f(lst): return sum(lst) f([1,2,3]) # 报错:TypeError: unhashable type: 'list' ``` ✅ 解决方案:把列表/字典转为**元组** ```python @lru_cache def f(t): return sum(t) f((1,2,3)) ``` ### 2. 不支持可变参数、全局变量、外部状态 如果函数结果**依赖全局变量/外部可变对象**,缓存会出错: ```python from functools import lru_cache num = 10 @lru_cache def get_num(x): return x + num get_num(1) # 11 num = 20 get_num(1) # 依旧返回 11(读旧缓存,不会感知全局变量变化) ``` **结论**:被装饰函数必须是**纯函数**(相同入参永远得到相同返回)。 --- # 常用内置方法 ### 1. 查看缓存信息 `cache_info()`:返回命名组 `hits(命中数), misses(未命中), maxsize(最大容量), currsize(当前数量)` ```python print(add.cache_info()) # CacheInfo(hits=1, misses=2, maxsize=None, currsize=2) ``` ### 2. 清空所有缓存 `cache_clear()`:手动清空缓存,重新开始计数 ```python add.cache_clear() ``` --- # 使用场景 ### 场景1:递归(斐波那契数列,最经典) 无缓存时递归重复计算,时间复杂度爆炸;加 `lru_cache` 直接优化到 O(n) ```python from functools import lru_cache @lru_cache(maxsize=None) def fib(n): if n <= 1: return n return fib(n-1) + fib(n-2) print(fib(30)) ``` ### 场景2:重复查询/IO 操作 网络请求、文件读取、数据库查询等慢操作,缓存结果减少开销: ```python @lru_cache(maxsize=128) def query_data(uid): # 模拟数据库查询 print("查询数据库") return f"用户{uid}数据" query_data(1001) query_data(1001) # 走缓存 ``` --- # 不用场景 1. 函数参数含 `list/dict/set` 且不方便转元组 2. 函数结果实时变化(接口、传感器、动态数据) 3. 调用频次极低,缓存收益小于内存开销 4. 需要分布式缓存(多机器共享)→ 改用 Redis 等 # 优缺点 ### 优点 1. 一行装饰器,开箱即用,零开发成本 2. 自动 LRU 淘汰,不用手动管理缓存 3. 大幅降低重复计算、IO、查询耗时 ### 缺点 & 注意事项 1. **仅支持可哈希参数**,列表、字典等无法直接使用 2. 占用内存:缓存结果常驻内存,大量数据慎用 3. 不适合结果频繁变化的非纯函数 4. 不支持多进程共享缓存(仅当前进程/线程生效) 原文出处:http://www.malaoshi.top/show_1GW3OtCAm92y.html