python惰性求值效果_让Python中类的属性具有惰性求值的能力
起步
我们希望将一个只读的属性定义为 property 属性方法,只有在访问它时才进行计算,但是,又希望把计算出的值缓存起来,不要每次访问它时都重新计算。
解决方案
定义一个惰性属性最有效的方法就是利用描述符类来完成它,示例如下:
class lazyproperty:
def __init__(self, fun):
self.fun = fun
def __get__(self, instance, owner):
if instance is None:
return self
value = self.fun(instance)
setattr(instance, self.fun.__name__, value)
return value
要使用这个工具,可以像下面的方式来使用它:
class Circle:
def __init__(self, radius):
self.radius = radius
@lazyproperty
def area(self):
print('Computing area')
return 3.1415 * self.radius ** 2
c = 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__() 才会被调用。
更多描述可见文档:
这种惰性求值的方法在很多模块中都会使用,比如django中的 cached_property:
使用上与例子一致,如表单中的 changed_data :
讨论
在大部分情况下,让属性具有惰性求值能力的全部意义就在于提升程序性能。当不需要这个属性时就能避免进行无意义的计算,同时又能阻止该属性重复进行计算。
本文的技巧中有一个潜在的缺点,就是计算出的值后就变成可变的(mutable)。
>>> c.area
78.53
>>> c.area = 3
>>> c.area
3
如果考虑可变性的问题,可以使用另一种实现方式,但执行效率会稍打折扣:
def lazyproperty(func):
name = '_lazy_' + func.__name__
@property
def lazy(self):
if hasattr(self, name):
return getattr(self, name)
value = func(self)
setattr(self, name, value)
return value
return lazy
如果使用这种方式,就会发现 set 操作是不允许的,所有的 get 操作都必须经由属性的 getter 函数来处理,这比直接在实例字典中查找相应的值要慢一些。
参考
python惰性求值效果_让Python中类的属性具有惰性求值的能力相关推荐
- python能做什么效果_一行 Python 能实现什么丧心病狂的功能?
发功之前友情提示:部分案例适用于Python3,在Windows下面可以用Python命令代替,具体请根据自己的修行选择. 一.江湖纯情版 1. 爱心 先来个高赞爱心的中英文结合版: print'\n ...
- python惰性求值_让Python中类的属性具有惰性求值的能力
起步 我们希望将一个只读的属性定义为 property 属性方法,只有在访问它时才进行计算,但是,又希望把计算出的值缓存起来,不要每次访问它时都重新计算. 解决方案 定义一个惰性属性最有效的方法就是利 ...
- 让Python中类的属性具有惰性求值的能力
起步 我们希望将一个只读的属性定义为 property 属性方法,只有在访问它时才进行计算,但是,又希望把计算出的值缓存起来,不要每次访问它时都重新计算. 解决方案 定义一个惰性属性最有效的方法就是利 ...
- python使用函数的目的_在Python 3.x中经常看到定义函数有一个单独的 * 参数?定义这样参数的目的是?怎样对其取值呢?...
参数在python中总是通过赋值进行传递的.在默认情况下,参数是通过其位置进行匹配的,从左到右,而且必须精确的传递和函数头部参数名一样多的参数. 这种默认的传递方式很简单 def f(a,b,c): ...
- python3 循环写入一对多键值对_为什么Python 3.6以后字典有序并且效率更高?
在Python 3.5(含)以前,字典是不能保证顺序的,键值对A先插入字典,键值对B后插入字典,但是当你打印字典的Keys列表时,你会发现B可能在A的前面. 但是从Python 3.6开始,字典是变成 ...
- list python 访问 键值对_基础|Python常用知识点汇总(中)
字符串字符串是 Python 中最常用的数据类型.我们可以使用引号('或")来创建字符串.1.创建字符串 str1 = 'Hello World!' str2 = "Hello W ...
- python教材答案编写函数求成绩平均数_学好Python例题之求成绩平均分
原博文 2019-08-16 21:03 − 例题: 用户输入若干个成绩,求所有成绩的平均值.每输入一个成绩后询问是否继续输入下一个成绩,回答yes就继续输入下一个成绩,回答no就停止输入成绩. 输入 ...
- python两个变量互换值编程_在编程中实现两个变量的值交换
在最初接触编程的时候,使用的是C语言,在交换两个变量的值的时候需要引入第三个变量作为temp值.如下面第①种方法. 方法①:加入第三个temp变量来实现交换 我们以C语言为例,也是最常见的方法 voi ...
- python求数组平均值_用python求一个数组的和与平均值的实现方法
用python求一个数组的和与平均值的实现方法 如下所示: # coding = GBK a =[1,2,3,4,5] sum=0 b = len(a) print("这个数组的长度为:&q ...
最新文章
- SpringBoot @Async Example
- mount查看linux分区大小,Linux磁盘管理----分区格式化挂载fdisk、mkfs、mount
- 开发函数计算的正确姿势——OCR 服务
- java html5 上传_HTML5结合ajax实现文件上传以及进度显示
- Mybatis(16)注解开发环境搭建
- python office库使用_看完这篇Python操作PPT总结,从此使用Python玩转Office全家桶就没有压力了!...
- html 选择自动增加行数,HTML怎么自动计算出上两行的值在第三行里面?
- 使用win10开启wifi移动热点解决软媒wifi助手开启失败问题
- 影像信息提取之——多时相影像动态检测
- matplotlib 绘图可视化知识点整理
- JVM调优工具的使用方法
- Web 字体 font-family 浅谈
- 拉新、复购、供应链,双11中小商家“三难”如何破?
- ORACLE-递归查询(分层查询)
- HMS Core 5,面试必问知识点
- Python安装pip时, 报错:zipimport.ZipImportError: can‘t decompress data; zlib not available 解决办法:
- ERP系统也有生产管理的功能,它与MES管理系统有什么差异
- R语言使用Metropolis- Hasting抽样算法进行逻辑回归
- 想要下载文章 但没有权限?——试试去文献对应的期刊官网碰碰运气
- 再见,Hotmail