让 Python 中类的属性具备惰性求值的能力

  • 时间:2018-08-21 23:07 作者:51reboot 来源:51reboot 阅读:739
  • 扫一扫,手机访问
摘要:起步我们希望将一个只读的属性定义为 property 属性方法,只有在访问它时才进行计算。但是,又希望把计算出的值缓存起来,不要每次访问它时都重新计算。处理方案定义一个惰性属性最有效的方法就是利使用形容符类来完成它,示例如下:class lazyproperty: def __init__(sel

起步

我们希望将一个只读的属性定义为 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 ** 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/reference/datamodel.html?#object.

这种惰性求值的方法在很多板块中都会用,比方 django 中的 cached_property:

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

探讨

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

本文的技巧中有一个潜在的缺点,就是计算出的值后就变成可变的(mutable)。

>>> c.area78.53>>> c.area = 3>>> c.area3

假如考虑可变性的问题,可以用另一种实现方式,但执行效率会稍打折扣:

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 函数来解决,这比直接在实例字典中查找相应的值要慢少量。

参考
  • https://docs.python.org/3/reference/datamodel.html?#object.
  • 《Python Cookbook 第三版》

作者:weapon
转载|原文链接:https://segmentfault.com/a/1190000016015066
(如有侵权,请联络删除)

最新声明通知

第 19 期【Python自动化运维入门】正在火热招生中
第 8 期 【Python自动化运维进阶】正在火热招生中

  • 全部评论(0)
最新发布的资讯信息
【系统环境|】从谷歌到手机厂商都下决心了,要清除32位应用这匹“害群之马”(2025-10-17 05:41)
【系统环境|】Windows上使用QEMU创建aarch64(ARM64)虚拟机(2025-10-17 05:40)
【系统环境|】nodejs 如何安装在aarch64平台(2025-10-17 05:39)
【系统环境|】常用git命令-从远程更新代码合并分支、提交代码等(2025-10-17 05:38)
【系统环境|】技术干货|常用的 Git 功能和选项(2025-10-17 05:38)
【系统环境|】掌握git命令,图解一目了然(2025-10-17 05:37)
【系统环境|】总结几个常用的Git命令的使用方法(2025-10-17 05:36)
【系统环境|】这篇 Git 教程太清晰了,很多 3 年经验程序员都收藏了(2025-10-17 05:35)
【系统环境|】Git常用命令及操作指南(2025-10-17 05:35)
【系统环境|】「实用」盘点那些开发中最常用的Git命令(2025-10-17 05:34)
手机二维码手机访问领取大礼包
返回顶部