起步

我们希望将一个只读的属性定义为 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中类的属性具有惰性求值的能力相关推荐

  1. python能做什么效果_一行 Python 能实现什么丧心病狂的功能?

    发功之前友情提示:部分案例适用于Python3,在Windows下面可以用Python命令代替,具体请根据自己的修行选择. 一.江湖纯情版 1. 爱心 先来个高赞爱心的中英文结合版: print'\n ...

  2. python惰性求值_让Python中类的属性具有惰性求值的能力

    起步 我们希望将一个只读的属性定义为 property 属性方法,只有在访问它时才进行计算,但是,又希望把计算出的值缓存起来,不要每次访问它时都重新计算. 解决方案 定义一个惰性属性最有效的方法就是利 ...

  3. 让Python中类的属性具有惰性求值的能力

    起步 我们希望将一个只读的属性定义为 property 属性方法,只有在访问它时才进行计算,但是,又希望把计算出的值缓存起来,不要每次访问它时都重新计算. 解决方案 定义一个惰性属性最有效的方法就是利 ...

  4. python使用函数的目的_在Python 3.x中经常看到定义函数有一个单独的 * 参数?定义这样参数的目的是?怎样对其取值呢?...

    参数在python中总是通过赋值进行传递的.在默认情况下,参数是通过其位置进行匹配的,从左到右,而且必须精确的传递和函数头部参数名一样多的参数. 这种默认的传递方式很简单 def f(a,b,c): ...

  5. python3 循环写入一对多键值对_为什么Python 3.6以后字典有序并且效率更高?

    在Python 3.5(含)以前,字典是不能保证顺序的,键值对A先插入字典,键值对B后插入字典,但是当你打印字典的Keys列表时,你会发现B可能在A的前面. 但是从Python 3.6开始,字典是变成 ...

  6. list python 访问 键值对_基础|Python常用知识点汇总(中)

    字符串字符串是 Python 中最常用的数据类型.我们可以使用引号('或")来创建字符串.1.创建字符串 str1 = 'Hello World!' str2 = "Hello W ...

  7. python教材答案编写函数求成绩平均数_学好Python例题之求成绩平均分

    原博文 2019-08-16 21:03 − 例题: 用户输入若干个成绩,求所有成绩的平均值.每输入一个成绩后询问是否继续输入下一个成绩,回答yes就继续输入下一个成绩,回答no就停止输入成绩. 输入 ...

  8. python两个变量互换值编程_在编程中实现两个变量的值交换

    在最初接触编程的时候,使用的是C语言,在交换两个变量的值的时候需要引入第三个变量作为temp值.如下面第①种方法. 方法①:加入第三个temp变量来实现交换 我们以C语言为例,也是最常见的方法 voi ...

  9. python求数组平均值_用python求一个数组的和与平均值的实现方法

    用python求一个数组的和与平均值的实现方法 如下所示: # coding = GBK a =[1,2,3,4,5] sum=0 b = len(a) print("这个数组的长度为:&q ...

最新文章

  1. SpringBoot @Async Example
  2. mount查看linux分区大小,Linux磁盘管理----分区格式化挂载fdisk、mkfs、mount
  3. 开发函数计算的正确姿势——OCR 服务
  4. java html5 上传_HTML5结合ajax实现文件上传以及进度显示
  5. Mybatis(16)注解开发环境搭建
  6. python office库使用_看完这篇Python操作PPT总结,从此使用Python玩转Office全家桶就没有压力了!...
  7. html 选择自动增加行数,HTML怎么自动计算出上两行的值在第三行里面?
  8. 使用win10开启wifi移动热点解决软媒wifi助手开启失败问题
  9. 影像信息提取之——多时相影像动态检测
  10. matplotlib 绘图可视化知识点整理
  11. JVM调优工具的使用方法
  12. Web 字体 font-family 浅谈
  13. 拉新、复购、供应链,双11中小商家“三难”如何破?
  14. ORACLE-递归查询(分层查询)
  15. HMS Core 5,面试必问知识点
  16. Python安装pip时, 报错:zipimport.ZipImportError: can‘t decompress data; zlib not available 解决办法:
  17. ERP系统也有生产管理的功能,它与MES管理系统有什么差异
  18. R语言使用Metropolis- Hasting抽样算法进行逻辑回归
  19. 想要下载文章 但没有权限?——试试去文献对应的期刊官网碰碰运气
  20. 再见,Hotmail

热门文章

  1. 双12压测引出的线上Full GC排查
  2. 面试:Java线程有哪几种状态,它们之间是如何切换的
  3. JEECG社区第六期架构培训班报名
  4. JEECG-V3 版本相关文档开放通知
  5. Java+sql server+CallableStatement调用存储过程三种情况 (转)
  6. Java描述设计模式(18):享元模式
  7. 概述嵌入式设备驱动,教你怎么“玩”转嵌入式开发
  8. 海润光伏上年净利扭亏“摘帽”在望
  9. js文件代码未加载或者没有js效果
  10. NET防SQL注入方法