让Python中类的属性具有惰性求值的能力
起步
我们希望将一个只读的属性定义为 property
属性方法,只有在访问它时才进行计算,但是,又希望把计算出的值缓存起来,不要每次访问它时都重新计算。
解决方案
定义一个惰性属性最有效的方法就是利用描述符类来完成它,示例如下:
class lazyproperty:def __init__(self, fun):self.fun = fundef __get__(self, instance, owner):if instance is None:return selfvalue = self.fun(instance)setattr(instance, self.fun.__name__, value)return value
要使用这个工具,可以像下面的方式来使用它:
class Circle:def __init__(self, radius):self.radius = radius@lazypropertydef area(self):print('Computing area')return 3.1415 * self.radius ** 2c = Circle(5)
print(c.area)
print(c.area)
可以看出,这里的实例方法 area()
只会被调用一次。
为什么会这样
如果类中定义了 __get__()
、__set__()
、__delete__()
中的任何方法,那么这个就被成为描述符(descriptor)。
一般情况下(我是说一般情况下),访问属性的默认行为是从对象的字典中获取,并沿着一个查找链的顺序进行搜索,比如对于 a.x
有一个查找链,从 a.__dict__['x']
然后是 type(a).__dict__['x']
,再继续通过 type(a)
的基类开始。
而如果查找的值是一个描述符对象,则会覆盖这个默认的搜索行为,优先采用描述符的行为,这个行为会因为如果调用而有些不同。这里就只说明例子中的情况。
如果描述符绑定的对象实例,a.x
则转换为调用: type(a).__dict__['x'].__get__(a, type(a))
。
当一个描述符之定义 __get__()
方法,则它的绑定关系比一般情况下要弱化很多。特别是,只有当被访问的属性不存在对象字典中时,__get__()
才会被调用。
更多描述可见文档:https://docs.python.org/3/ref...
这种惰性求值的方法在很多模块中都会使用,比如django中的 cached_property
:
讨论
在大部分情况下,让属性具有惰性求值能力的全部意义就在于提升程序性能。当不需要这个属性时就能避免进行无意义的计算,同时又能阻止该属性重复进行计算。
本文的技巧中有一个潜在的缺点,就是计算出的值后就变成可变的(mutable)。
>>> c.area
78.53
>>> c.area = 3
>>> c.area
3
如果考虑可变性的问题,可以使用另一种实现方式,但执行效率会稍打折扣:
def lazyproperty(func):name = '_lazy_' + func.__name__@propertydef lazy(self):if hasattr(self, name):return getattr(self, name)value = func(self)setattr(self, name, value)return valuereturn lazy
如果使用这种方式,就会发现 set
操作是不允许的,所有的 get 操作都必须经由属性的 getter
函数来处理,这比直接在实例字典中查找相应的值要慢一些。
参考
让Python中类的属性具有惰性求值的能力相关推荐
- python惰性求值_让Python中类的属性具有惰性求值的能力
起步 我们希望将一个只读的属性定义为 property 属性方法,只有在访问它时才进行计算,但是,又希望把计算出的值缓存起来,不要每次访问它时都重新计算. 解决方案 定义一个惰性属性最有效的方法就是利 ...
- python惰性求值效果_让Python中类的属性具有惰性求值的能力
起步 我们希望将一个只读的属性定义为 property 属性方法,只有在访问它时才进行计算,但是,又希望把计算出的值缓存起来,不要每次访问它时都重新计算. 解决方案 定义一个惰性属性最有效的方法就是利 ...
- python中关系运算符惰性求值_python对象属性惰性取值
python面向对象进阶 在知乎上面看到这个如何让python对象属性具有惰性求值的能力,认真学习了一番,记录一下. __setattr__.__getattr__.__delattr__ class ...
- python中and和or的惰性求值特点_Python中的惰性评估
一个名为python pattern和Wikipedia的github存储库告诉我们什么是惰性评估. 将expr的评估延迟到需要其值为止,并避免重复评估. python3中的cached_proper ...
- python中and和or的惰性求值特点_惰性求值和yield-Python
惰性求值 惰性求值(Lazy evaluation)是在需要时才进行求值的计算方式.表达式不在它被绑定到变量之后就立即求值,而是在该值被取用的时候求值. 除可以得到性能的提升(更小的内存占用)外,惰性 ...
- python惰性求值的特点_C#教程之C#函数式编程中的惰性求值详解
https://www.xin3721.com/eschool/python.html 惰性求值 在开始介绍今天要讲的知识之前,我们想要理解严格求值策略和非严格求值策略之间的区别,这样我们才能够深有体 ...
- python中and和or的惰性求值特点_python中的惰性求值
可能经常会有人问到python中的range和xrange有什么区别,你知道range是直接创建了一个列表,而xrange是创建了一个生成器,并且xrange非常适合当需要创建一个很大的列表的时候,因 ...
- python中关系运算符惰性求值,lazy.js 惰性求值实现分析
背景:惰性求值? 来看一个 lazy.js 主页提供的示例: var people = getBigArrayOfPeople(); var results = _.chain(people) .pl ...
- python惰性求值例子_惰性求值和yield-Python
惰性求值 惰性求值(Lazy evaluation)是在需要时才进行求值的计算方式.表达式不在它被绑定到变量之后就立即求值,而是在该值被取用的时候求值. 除可以得到性能的提升(更小的内存占用)外,惰性 ...
最新文章
- arduino如何调用mysql,【 实测可用 】Arduino 直接访问 mysql
- LM358的工作特性测试
- sdut 2136 数据结构实验之二叉树的建立与遍历
- 初等数学O 集合论基础 第一节 集合及其基本运算、de Moivre公式
- web前端网页设计作业_网页前端设计快速入门技巧
- TOYS-POJ2318
- php swoole 项目实战,Laravel 中使用 swoole 项目实战开发案例一 (建立 swoole 和前端通信)...
- 部署superset_ubuntu16下部署apache superset趟坑指南(内有福利)
- 基于PCL的ICP及其变种算法实现
- java cpu高_Java中的CPU占用高和内存占用高的问题排查
- 【BZOJ1500】[NOI2005]维修数列
- Wireshark实战分析之DHCP协议(二)
- nero linux4 序列号,nero9序列号_可以永久使用的nero9序列号
- 电信光猫 友华PT921G 研究
- centos7 yum安装时遇到错误:Header V3 RSA/SHA256 Signature, key ID 352c64e5: NOKEY
- STM32CUBEMX 配置12脚3641BS以及串口显示RTC时间
- 14.0高等数学五- 函数的幂级数展开(泰勒级数或者麦克劳林级数)
- 飞php影视系统,i.php · 姬晓亮/海洋cms 海洋影视管理系统 - 免费开源PHP - Gitee.com...
- 服务器 战地4 无限载入,战地4卡在loading界面无限载入怎么办
- 小米8探索版线刷兼救砖_解账户锁_纯净刷机包_教程
热门文章
- 【C/C++】代码换行问题
- mysql字段说明_mysql 字段类型说明
- 三种excel 多条件计数方法
- Google Guava 库用法整理
- Oracle数据库中序列(SEQUENCE)的用法详解
- ORACLE的所有字段类型
- Transaction rolled back because it has been marked as rollback-only
- 2016级算法第六次上机-A.Bamboo之寻找小金刚
- ●HDU 2871 Memory Control(Splay)
- [Everyday Mathematics]20150203