0. 一句话定位
| 维度 | 内容 |
|---|---|
| 作用对象 | 类实例方法 |
| 使用场景 | 属性访问 |
| 来源 | 标准库 functools.cached_property(3.8+) |
| 语法形式 | @cached_property |
1. 做什么
第一次访问 obj.attr 时执行方法并把返回值写入实例 __dict__;之后访问直接读缓存,不再调用方法。适用于依赖 self、计算成本高、结果在实例生命周期内不变的数据。
2. 重点参数
| 参数 | 类型 | 默认值 | 作用 | 配置建议 |
|---|---|---|---|---|
func |
callable | — | 被装饰方法 | 无参装饰器;方法首参为 self |
无额外配置项;缓存键为属性名,存于实例字典。
3. 最小可运行示例
1 | from functools import cached_property |
4. 常见变体
清除缓存(测试或数据变更后)
1 | del ds.size # 删除实例属性,下次访问重新计算 |
与 @property 对比
1 |
|
5. 适用 / 不适用
适用
- 依赖实例状态、首次计算后不变的属性(解析配置、统计量)
- 比
@lru_cache更符合「每个实例一份缓存」语义
不适用
- 底层数据会变而缓存不刷新 → 用
@property或手动失效 - 类级共享缓存、与
self无关 →@lru_cacheon 静态/模块函数 - 需要 setter → 用
@property
6. 易踩坑
- 缓存后不会随
self.path等依赖自动更新;变更后须del obj.attr - 不能用于无
self的类方法(3.8+ 仅实例方法;类级见classmethod+ 其他模式) - 多线程首次并发访问可能重复计算(一般可接受);要严格单次用锁
- 与
__slots__联用时须确保 slotted 类支持写入该属性名
7. 近邻替代
| 替代 | 何时用 |
|---|---|
@property |
每次访问都需最新值 |
@lru_cache |
纯函数、参数可哈希、跨实例共享 |
手动 self._cache = None |
需精细控制失效逻辑 |