functools:lru_cache 与 cached_property
使用 lru_cache 和 cached_property 缓存开销较大的计算。
functools:lru_cache 与 cached_property 是 CoddyKit 上的免费 Python Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Python Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Python Academy 课程共包含 4 节课。
什么是记忆化?
记忆化会根据函数参数缓存函数调用的结果。使用相同参数重复调用时,会立即返回缓存的结果。
def slow_fib(n):
if n < 2: return n
return slow_fib(n-1) + slow_fib(n-2)
# slow_fib(35) makes ~29 million calls
# With caching it makes only 35@lru_cache
@functools.lru_cache(maxsize=128) 最多缓存 maxsize 个最近的结果。将 maxsize=None 设置为无限缓存。
import functools
@functools.lru_cache(maxsize=None)
def fib(n):
if n < 2: return n
return fib(n-1) + fib(n-2)
print(fib(50)) # instant@cache — Python 3.9+
functools.cache 是 lru_cache(maxsize=None) 的简写形式,表示无限缓存,并且名称更加简洁。
import functools
@functools.cache
def factorial(n):
return n * factorial(n-1) if n else 1
print(factorial(10)) # 3628800缓存信息与清除
经过缓存的函数会提供 .cache_info()(命中次数、未命中次数和大小)以及 .cache_clear()。
import functools
@functools.lru_cache(maxsize=100)
def square(n):
return n * n
for i in range(5): square(i % 3)
print(square.cache_info())
# CacheInfo(hits=2, misses=3, maxsize=100, currsize=3)
square.cache_clear()LRU 淘汰策略
当缓存已满时,LRU(最近最少使用)会淘汰最近访问次数最少的项目。
import functools
@functools.lru_cache(maxsize=3)
def compute(n):
print(f"computing {n}")
return n**2
for x in [1,2,3,4,1]: # 4 evicts 1 (LRU), then 1 re-computes
compute(x)仅支持可哈希参数
lru_cache 要求所有参数都可哈希。列表和字典不可哈希,请改用元组。
import functools
@functools.lru_cache(maxsize=None)
def sum_tuple(t): # tuple is hashable
return sum(t)
print(sum_tuple((1,2,3))) # 6
# sum_tuple([1,2,3]) # TypeError@cached_property
functools.cached_property 只计算一次属性,并将结果缓存到实例上,用该值替换描述符。
import functools
class Circle:
def __init__(self, r):
self.r = r
@functools.cached_property
def area(self):
import math
print("computing...")
return math.pi * self.r ** 2
c = Circle(5)
print(c.area) # computing... 78.53...
print(c.area) # 78.53... (cached, no print)cached_property 与 property 的比较
@property 每次访问时都会重新计算。@cached_property 只计算一次,并将结果存储在 instance.__dict__ 中。
import functools
class Expensive:
@property
def always(self): # runs every access
return sum(range(1_000_000))
@functools.cached_property
def once(self): # runs only first access
return sum(range(1_000_000))cached_property 的线程安全性
cached_property 不是线程安全的。如果多个线程同时访问它,计算可能会执行多次。如有需要,请使用锁。
import functools, threading
class SafeCache:
_lock = threading.Lock()
@functools.cached_property
def data(self):
with self._lock:
return expensive_computation()使 cached_property 缓存失效
删除实例属性即可使缓存失效,并强制下次访问时重新计算。
import functools
class Report:
@functools.cached_property
def summary(self):
return compute_summary()
r = Report()
_ = r.summary # computed
del r.summary # invalidate
_ = r.summary # recomputed使用 lru_cache 作为 API 缓存
为一个会话缓存 API 响应,以避免重复的网络调用。需要新数据时,请清除缓存。
import functools, urllib.request, json
@functools.lru_cache(maxsize=32)
def get_user(user_id):
url = f"https://api.example.com/users/{user_id}"
with urllib.request.urlopen(url) as r:
return json.loads(r.read())
user = get_user(42) # network call
user = get_user(42) # cached快速检查
哪个方法可以清除使用 @lru_cache 装饰的函数的所有缓存结果?
复习
@lru_cache 根据参数缓存函数结果(参数必须可哈希)。@cache 是无限缓存的别名。@cached_property 会为每个实例缓存一次属性计算结果。请使用 cache_info() 查看信息,并使用 cache_clear() 重置缓存。
常见问题解答
「functools:lru_cache 与 cached_property」课时是免费的吗?
是的 — 「functools:lru_cache 与 cached_property」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Python Academy 课程的其余内容,请升级到 CoddyKit PRO。 Python Academy 课程共包含 4 节课。
「functools:lru_cache 与 cached_property」这节课中我会学到什么?
使用 lru_cache 和 cached_property 缓存开销较大的计算。 你通过在浏览器中直接运行的动手代码来练习 Python Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Python Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Python Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「functools:lru_cache 与 cached_property」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Python Academy 课中编写并运行代码吗?
能。每节 Python Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- itertools:无限与有限迭代器
- itertools:组合数学
- functools:partial 与 reduce
- functools:lru_cache 与 cached_property