起步

我们希望将一个只读的属性定义为 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

使用上与例子一致,如表单中的 changed_data :

讨论

在大部分情况下,让属性具有惰性求值能力的全部意义就在于提升程序性能。当不需要这个属性时就能避免进行无意义的计算,同时又能阻止该属性重复进行计算。

本文的技巧中有一个潜在的缺点,就是计算出的值后就变成可变的(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 函数来处理,这比直接在实例字典中查找相应的值要慢一些。

参考

  1. https://docs.python.org/3/ref...
  2. 《Python Cookbook 第三版》

让Python中类的属性具有惰性求值的能力相关推荐

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

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

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

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

  3. python中关系运算符惰性求值_python对象属性惰性取值

    python面向对象进阶 在知乎上面看到这个如何让python对象属性具有惰性求值的能力,认真学习了一番,记录一下. __setattr__.__getattr__.__delattr__ class ...

  4. python中and和or的惰性求值特点_Python中的惰性评估

    一个名为python pattern和Wikipedia的github存储库告诉我们什么是惰性评估. 将expr的评估延迟到需要其值为止,并避免重复评估. python3中的cached_proper ...

  5. python中and和or的惰性求值特点_惰性求值和yield-Python

    惰性求值 惰性求值(Lazy evaluation)是在需要时才进行求值的计算方式.表达式不在它被绑定到变量之后就立即求值,而是在该值被取用的时候求值. 除可以得到性能的提升(更小的内存占用)外,惰性 ...

  6. python惰性求值的特点_C#教程之C#函数式编程中的惰性求值详解

    https://www.xin3721.com/eschool/python.html 惰性求值 在开始介绍今天要讲的知识之前,我们想要理解严格求值策略和非严格求值策略之间的区别,这样我们才能够深有体 ...

  7. python中and和or的惰性求值特点_python中的惰性求值

    可能经常会有人问到python中的range和xrange有什么区别,你知道range是直接创建了一个列表,而xrange是创建了一个生成器,并且xrange非常适合当需要创建一个很大的列表的时候,因 ...

  8. python中关系运算符惰性求值,lazy.js 惰性求值实现分析

    背景:惰性求值? 来看一个 lazy.js 主页提供的示例: var people = getBigArrayOfPeople(); var results = _.chain(people) .pl ...

  9. python惰性求值例子_惰性求值和yield-Python

    惰性求值 惰性求值(Lazy evaluation)是在需要时才进行求值的计算方式.表达式不在它被绑定到变量之后就立即求值,而是在该值被取用的时候求值. 除可以得到性能的提升(更小的内存占用)外,惰性 ...

最新文章

  1. arduino如何调用mysql,【 实测可用 】Arduino 直接访问 mysql
  2. LM358的工作特性测试
  3. sdut 2136 数据结构实验之二叉树的建立与遍历
  4. 初等数学O 集合论基础 第一节 集合及其基本运算、de Moivre公式
  5. web前端网页设计作业_网页前端设计快速入门技巧
  6. TOYS-POJ2318
  7. php swoole 项目实战,Laravel 中使用 swoole 项目实战开发案例一 (建立 swoole 和前端通信)...
  8. 部署superset_ubuntu16下部署apache superset趟坑指南(内有福利)
  9. 基于PCL的ICP及其变种算法实现
  10. java cpu高_Java中的CPU占用高和内存占用高的问题排查
  11. 【BZOJ1500】[NOI2005]维修数列
  12. Wireshark实战分析之DHCP协议(二)
  13. nero linux4 序列号,nero9序列号_可以永久使用的nero9序列号
  14. 电信光猫 友华PT921G 研究
  15. centos7 yum安装时遇到错误:Header V3 RSA/SHA256 Signature, key ID 352c64e5: NOKEY
  16. STM32CUBEMX 配置12脚3641BS以及串口显示RTC时间
  17. 14.0高等数学五- 函数的幂级数展开(泰勒级数或者麦克劳林级数)
  18. 飞php影视系统,i.php · 姬晓亮/海洋cms 海洋影视管理系统 - 免费开源PHP - Gitee.com...
  19. 服务器 战地4 无限载入,战地4卡在loading界面无限载入怎么办
  20. 小米8探索版线刷兼救砖_解账户锁_纯净刷机包_教程

热门文章

  1. 【C/C++】代码换行问题
  2. mysql字段说明_mysql 字段类型说明
  3. 三种excel 多条件计数方法
  4. Google Guava 库用法整理
  5. Oracle数据库中序列(SEQUENCE)的用法详解
  6. ORACLE的所有字段类型
  7. Transaction rolled back because it has been marked as rollback-only
  8. 2016级算法第六次上机-A.Bamboo之寻找小金刚
  9. ●HDU 2871 Memory Control(Splay)
  10. [Everyday Mathematics]20150203