什么是惰性属性?

Posted

技术标签:

【中文标题】什么是惰性属性?【英文标题】:What is a lazy property? 【发布时间】:2014-09-02 10:59:18 【问题描述】:

在网上浏览 webapp2 文档时,我发现了关于装饰器的信息:webapp2.cached_property

在文档中,它说:

将函数转换为惰性属性的装饰器。

我的问题是:

【问题讨论】:

【参考方案1】:

它是一个 property 装饰器,在第一次调用后就让开。它允许您自动缓存计算值。

standard library @property decorator 是一个data descriptor object,并且总是被调用,即使在同名的实例上有一个属性。

另一方面,@cached_property 装饰器只有有一个__get__ 方法,这意味着如果已经存在同名的属性,则不会调用它。它通过在第一次调用时在实例上设置具有相同名称的属性来利用这一点。

给定一个名为 foo 的实例上的 @cached_property-decorated bar 方法,会发生以下情况:

Python 解析 foo.bar。在实例上找不到bar 属性。

Python 在类上找到bar 描述符,并在其上调用__get__

cached_property__get__ 方法调用修饰的bar 方法。

bar 方法进行计算,并返回字符串'spam'

cached_property__get__ 方法获取返回值并在实例上设置一个新属性barfoo.bar = 'spam'.

cached_property__get__ 方法返回 'spam' 返回值。

如果您再次请求foo.bar,Python 会在实例上找到bar 属性,并从这里开始使用它。

另见source code for the original Werkzeug implementation:

# implementation detail: this property is implemented as non-data
# descriptor.  non-data descriptors are only invoked if there is
# no entry with the same name in the instance's __dict__.
# this allows us to completely get rid of the access function call
# overhead.  If one choses to invoke __get__ by hand the property
# will still work as expected because the lookup logic is replicated
# in __get__ for manual invocation.

请注意,从 Python 3.8 开始,标准库有一个类似的对象,@functools.cached_property()。它的实现更加健壮,它可以防止以不同的名称意外重用,如果在没有__dict__ 属性的对象或该对象不支持项目分配的对象上使用会产生更好的错误消息,并且是也是线程安全的。

【讨论】:

在 Python-3.8 中添加了一个 functools.cached_property @martineau:是的,感谢您在这个答案上戳我。我在我的答案中添加了对该版本的简短介绍。

以上是关于什么是惰性属性?的主要内容,如果未能解决你的问题,请参考以下文章

惰性属性被多次初始化的潜在影响是啥?

从属属性中的 MATLAB 惰性求值

Swift 中的惰性属性相当于 Objective C 中的惰性 Init getter

Swift 中的惰性只读属性

SwiftUI 中的惰性属性

多次加载的 Swift 惰性变量(计算属性?)