functools.lru_cache和cache缓存装饰器详解
请详解functools.lru_cache和functools.cache(Python 3.9+)装饰器的用途、参数、工作原理、性能优化案例,以及和自定义缓存装饰器的对比。为什么cache比lru_cache更快?
回答
专业代码师
lru_cache(Least Recently Used)
from functools import lru_cache
@lru_cache(maxsize=128, typed=False)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
- maxsize: 最大缓存条目,
None表示无限制 - typed:
True时区分1和1.0(不同类型视为不同key) - 淘汰策略: LRU,缓存满时淘汰最久未使用的项
- 方法:
cache_info()、cache_clear()、cache_parameters()
cache(Python 3.9+,无大小限制)
from functools import cache
@cache
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
- 等价于
lru_cache(maxsize=None) - 更快:因为不维护LRU淘汰逻辑(无双向链表和哈希表更新开销)
- 适合缓存大小可控的场景(如纯函数、参数空间有限)
工作原理
底层使用字典存储{args_tuple: return_value}。lru_cache额外维护一个双向链表跟踪访问顺序。
自定义缓存装饰器
from functools import wraps
def simple_cache(func):
cache = {}
@wraps(func)
def wrapper(*args, **kwargs):
key = args + tuple(sorted(kwargs.items()))
if key not in cache:
cache[key] = func(*args, **kwargs)
return cache[key]
return wrapper
**自定义优点:**支持TTL过期、文件持久化、分布式缓存等。
性能对比
| 场景 | 无缓存 | lru_cache(128) | cache |
|---|---|---|---|
| fib(35) | ~5s | ~0.0001s | ~0.0001s |
| 加速比 | 1x | 50000x | 50000x |
**注意:**缓存参数必须可哈希。list、dict等可变类型需转为tuple。