探索 Python 的 functools 模块:缓存、属性缓存与 LRU 缓存

李升伟 编译

Python 的 functools 模块是函数式编程爱好者的宝库,提供了许多工具来提升代码的效率和优雅性。本文将深入探讨三个强大的函数------cache、cached_property 和 lru_cache,它们通过存储昂贵计算的结果来优化性能。无论是加速递归算法还是简化基于类的计算,这些工具都能满足需求。让我们通过清晰的解释和实际示例逐一探索。

1. cache:简单无界的记忆化

cache 装饰器是一种轻量级的函数结果记忆化方法,通过存储结果以便在相同输入再次出现时复用。它就像给函数的输出贴了便利贴------无需重复计算!

工作原理

作用 :将函数结果存储在一个无界字典中,以参数作为键。
适用场景 :适用于纯函数(相同输入产生相同输出且计算成本高的函数)。
核心特性 :等同于 lru_cache(maxsize=None),但因简单性更快。

示例

python 复制代码
from functools import cache

@cache
def factorial(n):
    return n * factorial(n-1) if n else 1

print(factorial(10))  # 计算:3628800
print(factorial(10))  # 返回缓存结果,无需重新计算

为什么它很强大?

速度 :避免冗余计算,使递归函数(如阶乘)变得飞快。
简洁性 :无需配置,直接添加装饰器即可。
注意事项:缓存会无限增长,需监控内存使用(尤其对输入种类多的函数)。

2. cached_property:单次计算属性

cached_property 装饰器将类方法转换为仅计算一次并缓存结果的属性。它类似于惰性加载的属性,但结果会持久保留。

工作原理

作用 :首次访问时运行方法,将结果缓存为实例属性,后续访问直接返回缓存值。
适用场景 :适用于类中需要一次性计算且结果不变的昂贵操作。
核心特性 :仅适用于实例方法(需包含 self)。

示例

python 复制代码
from functools import cached_property

class Circle:
    def __init__(self, radius):
        self.radius = radius

    @cached_property
    def area(self):
        print("正在计算面积")
        return 3.14159 * self.radius ** 2

c = Circle(5)
print(c.area)  # 输出:正在计算面积,然后 78.53975
print(c.area)  # 输出:78.53975(缓存结果,无需重新计算)

为什么它很强大?

效率 :每个实例仅计算一次,节省 CPU 资源。
代码简洁 :像属性一样使用(c.area 而非 c.area()),无缝融入类设计。
注意事项:缓存值可被覆盖(如 c.area = 0),因此仅适用于不可变数据。

3. lru_cache:灵活的有界记忆化

lru_cache 装饰器是记忆化的"重型武器",提供基于最近最少使用(LRU)的可配置容量缓存。它线程安全且支持内省功能,是优化复杂函数的首选工具。

工作原理

作用 :最多缓存 maxsize 个结果,当缓存满时移除最近最少使用的条目。支持 typed 选项,将不同类型的参数(如 3 和 3.0)视为不同键。
适用场景 :适用于递归算法、动态规划或重复调用的函数。
核心特性 :提供 cache_info() 方法,可查看命中数、未命中数、缓存容量等信息。

示例

python 复制代码
from functools import lru_cache

@lru_cache(maxsize=32)
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

print(fib(10))  # 计算:55
print(fib.cache_info())  # 输出:CacheInfo(hits=8, misses=11, maxsize=32, currsize=11)

为什么它很强大?

控制 :通过 maxsize 平衡内存与性能(None 表示无界,类似 cache)。
线程安全 :适用于多线程环境,确保缓存一致性。
调试支持 :cache_info() 帮助优化性能,揭示缓存效果。
注意事项:避免用于有副作用的函数,因其假设输出是确定性的。

总结

cache :简单无界的记忆化,适合纯函数。
cached_property :单次计算的类属性,适合惰性加载。
lru_cache :灵活的 LRU 缓存,适合复杂场景。

通过合理使用这些工具,可以显著提升 Python 代码的性能和可读性!

原文链接:https://dev.to/coderatul/cache-in-python--18g

相关推荐
代码山河6 小时前
Python就业方向全解析:后端、爬虫、数据分析、AI你选哪个?
python·学习·架构·教程·面向对象·项目
在世修行6 小时前
智学文枢:题目流水线
python·多线程·状态机·pyside
梯度下降者6 小时前
零基础入门Python 爬虫
爬虫·python·数据分析·入门指南·webcrawler
“AI国潮设计-小江”8 小时前
【AIGC实战】Python+Stable Diffusion打造“英歌舞财神”IP,解锁“马到成功”等爆款情绪营销文案设计
开发语言·人工智能·python·prompt·aigc
benchmark_cc9 小时前
用 Python 拉 A 股全市场实时快照:Notebook 请求、结果校验与易错点
python·数据分析·pandas·量化交易·股票数据·quantdash
伞伞悦读9 小时前
【第70期】Adam二阶矩不是方差:偏差校正、动量与AdamW完整实验
python
外收内放9 小时前
Python基础语法练习题(73)
java·前端·python
锋行天下10 小时前
Langgraph HITL 中断运行,用户输入后输出打字效果
人工智能·python
时早玖沐10 小时前
给 AstrBot 写一个天气推送插件:12 次提交、6 个坑
python·开源·ai编程
触底反弹10 小时前
🚀 FastAPI 五大重难点深度剖析:从 500 报错到彻底搞懂 Depends、Pydantic 与 SQLAlchemy
python·fastapi