摘要:更多描述可见文档这种惰性求值的方法在很多模块中都会使用,比如中的使用上与例子一致,如表单中的讨论在大部分情况下,让属性具有惰性求值能力的全部意义就在于提升程序性能。当不需要这个属性时就能避免进行无意义的计算,同时又能阻止该属性重复进行计算。
起步
我们希望将一个只读的属性定义为 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__() 才会被调用。
更多描述可见文档: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__ @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/ref...
《Python Cookbook 第三版》
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/42231.html
摘要:官方也宣布在停止对的维护。并且在很多面试过程中,面试官都会问与的区别。的版本,常被称为,或简称。与部分地支持这种形式的语法。捕获异常的语法由改为。在中,表示八进制字面量的方式只有一种,就是。已经支援新的模组。 前言 如果你是刚接触 Python 的初学者,那你可能是直接学习 Python 3.x 版本。对于 Python 2.x 的版本是不会有所接触。官方也宣布在 2020 停止对 P...
摘要:纯函数式状态随机数生成器很明显,原有的函数不是引用透明的,这意味着它难以被测试组合并行化。售货机在输出糖果时忽略所有输入本章知识点惰性求值函数式状态 第二节 惰性求值与函数式状态 在下面的代码中我们对List数据进行了一些处理 List(1,2,3,4).map(_ + 10).filter(_ % 2 == 0).map(_ * 3) 考虑一下这段程序是如何求值的,如果我们跟踪一下...
摘要:声明式编程一种编程范式,与命令式编程相对立。常见的声明式编程语言有数据库查询语言,正则表达式逻辑编程函数式编程组态管理系统等。函数式编程,特别是纯函数式编程,尝试最小化状态带来的副作用,因此被认为是声明式的。 编程范式与函数式编程 一、编程范式的分类 常见的编程范式有:函数式编程、程序编程、面向对象编程、指令式编程等。在面向对象编程的世界,程序是一系列相互作用(方法)的对象(Class...
摘要:同时还定义了接口,使得其下级可以从这里得到一个迭代器,对于该进行遍历。迭代器在中也是一个约定的协议,实现该协议的对象要支持和两个接口方法。从迭代器的逻辑中,可以看到,当对象作为其他的上级时,如果实现上传下达。 背景:惰性求值? 来看一个 lazy.js 主页提供的示例: var people = getBigArrayOfPeople(); var results = _.chain(...
摘要:初始化和配置对象关系映射。的则需要在中声明。例如配置信息中指出是可以绑定多个数据库引擎。是通过解决一对多的关系。将会返回学院学生人数将会返回学生的学院信息的类实例。处理关系对象查询中有详细的说明。 初始化和配置 ORM(Object Relational Mapper) 对象关系映射。指将面对对象得方法映射到数据库中的关系对象中。Flask-SQLAlchemy是一个Flask扩展,能...
阅读 448·2021-10-09 09:57
阅读 444·2019-08-29 18:39
阅读 792·2019-08-29 12:27
阅读 3010·2019-08-26 11:38
阅读 2636·2019-08-26 11:37
阅读 1268·2019-08-26 10:59
阅读 1347·2019-08-26 10:58
阅读 966·2019-08-26 10:48