如何实现一个只在第一次访问时计算的属性(lazy property)
技术百科
冷炫風刃
发布时间:2026-01-27
浏览: 次 Python中可用@property配合实例属性实现lazy计算,首次访问时计算并缓存,后续直接返回;推荐使用Python 3.8+的functools.cached_property,线程安全且更可靠。
Python 中用 @property + 实例变量实现 lazy 计算
Python 没有原生的 lazy property,但可以靠手动缓存实现:首次访问时计算并存到实例属性,后续直接返回缓存值。关键在于避免重复计算,且不污染类定义。
常见错误是把缓存写在类属性里(导致所有实例共享),或每次访问都重新计算(失去 lazy 意义)。
- 在
__init__里不预计算,只设一个私有属性(如self._expensive_value = None) - 在
@property方法里检查该属性是否为None(或用hasattr(self, '_expensive_value')更稳妥,因为None可能是合法计算结果) - 若未计算,则执行逻辑并赋值;否则直接返回
class DataProcessor:
@property
def pars
ed_data(self):
if not hasattr(self, '_parsed_data'):
self._parsed_data = self._load_and_parse() # 耗时操作
return self._parsed_data
用 functools.cached_property(Python 3.8+)最简方案
这是标准库提供的官方 lazy property 实现,自动处理线程安全、只读、缓存存储位置等细节,比手写更可靠。
注意它只能用于实例属性,不能用于类方法或静态方法;且一旦计算完成,缓存值不可修改(属性只读)。
- 必须是 Python 3.8 或更新版本
- 装饰的是方法,但行为像属性(无括号调用)
- 缓存存在实例的
__dict__中,删除实例属性即可重置(del obj.attr)
from functools import cached_propertyclass ConfigLoader: @cached_property def config(self): return load_config_from_disk() # 模拟 IO
JavaScript 中用 get + Object.defineProperty 模拟
JS 的 getter 默认每次触发函数体,要实现 lazy 必须手动缓存。常见做法是在对象上挂一个私有字段(如 _cachedValue),并在 getter 中判断。
容易踩的坑:用 this.value 自身触发 getter 导致无限递归;或者在箭头函数中丢失 this 绑定。
- 推荐用
Object.defineProperty显式控制,避免污染原型 - 缓存字段名建议加下划线前缀,明确其非公开性
- 如果需要重置缓存,可暴露一个
invalidate方法
function createLazyObject() {
const obj = {};
Object.defineProperty(obj, 'items', {
get() {
if (!('_items' in obj)) {
obj._items = expensiveFetch();
}
return obj._items;
}
});
return obj;
}
为什么不用 __getattr__ 或描述符做通用 lazy wrapper?
虽然可行,但实际项目中容易引入隐式行为和调试困难。比如 __getattr__ 是兜底方法,会拦截所有未定义属性,干扰 IDE 补全和类型检查;自定义描述符则需额外管理实例字典键名,增加出错概率。
真正需要通用方案的场景很少——多数 lazy 属性语义明确、数量有限。硬套通用 wrapper 反而让代码更难追踪数据来源。
复杂点在于:lazy 属性可能依赖其他 lazy 属性,形成链式计算;此时要注意初始化顺序和循环依赖。这类情况最好显式拆解依赖,而不是靠自动缓存机制掩盖问题。
# python
# app
# js
# 循环
# 递归
# Property
# javascript
# java
# 标准库
# 为什么
# 线程
# Object
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- Windows10系统怎么查看运行时间_Win10
- 用lighttpd能运行php吗_lighttpd
- 如何在 Go 中比较自定义的数组类型(如 [20]
- php8.4如何配置ssl证书_php8.4htt
- 微信JSAPI支付回调PHP怎么接收_处理JSAP
- c++20的std::format怎么用 比pri
- windows如何修改文件默认打开方式_windo
- Win11玩游戏全屏闪退怎么办_Win11全屏优化
- 如何用::实现工具类方法调用_php静态工具类设计
- MAC怎么截图并快速编辑_MAC自带截图快捷键与标
- Win11触摸板没反应怎么办_开启Win11笔记本
- Win10怎么卸载爱奇艺_Win10彻底卸载爱奇艺
- MAC如何启用访达侧边栏显示_MAC Finder
- 微信里的php文件怎么变mp4_微信接收php转m
- Windows10如何重置此电脑_Windows1
- MAC的“接续互通”功能无法使用怎么办_MAC检查
- 如何将文本文件中的竖排字符串转换为横排字符串
- Win11怎么开启游戏模式_Win11优化游戏帧数
- PHP主流架构怎么部署到Docker_容器化流程【
- c++中如何进行二进制文件读写_c++ read与
- Win11右键反应慢怎么办 Win11优化右键菜单
- Win11怎么关闭边缘滑动手势_Windows11
- Win10如何更改开机密码_Windows10登录
- Win11怎么设置默认邮件客户端 Win11修改M
- 本地php环境打开php文件直接下载_浏览器解析p
- Python对象生命周期管理_创建销毁解析【教程】
- php串口通信波特率怎么选_根据硬件手册设置正确波
- Win11怎么用设置清理回收站_Win11设置清理
- Win11怎么打开旧版计算器_Win11恢复传统计
- 如何在 Go 中创建包含映射(map)的切片(sl
- Win11怎么清理C盘下载文件夹_Win11清理下
- Python日志系统设计与实现_高可观测性架构实战
- Windows电脑键盘突然失灵怎么办?(驱动与硬件
- 如何在 Go 中调用动态链接库(.so)中的函数
- Windows蓝屏错误0x00000023怎么修复
- mac怎么查看wifi密码_MAC查看已连接WiF
- windows如何禁用驱动程序强制签名_windo
- php删除数据怎么清空表_truncate与del
- Win11怎么关闭开机声音_Win11系统启动提示
- Win11怎么关闭SmartScreen_禁用Wi
- 如何在 VS Code 中正确配置并使用 NumP
- c++如何获取map中所有的键_C++遍历键值对提
- 如何使用Golang搭建本地API测试环境_快速验
- Python网页解析流程_html结构说明【指导】
- c++如何利用doxygen生成开发文档_c++
- Python异步编程高级项目教程_asyncio协
- Win11怎么清理C盘OneDrive缓存_Win
- Win11怎么设置触控板手势_Windows11三
- 如何使用Golang安装依赖库_管理模块和第三方包
- php在Linux怎么部署_LNMP环境搭建PHP


QQ客服