python - 让@property 只运行一次
问题描述
我有以下示例:
class A:
value = None
@property
def value(self):
if not value:
result = <do some external call>
self.value = result
return self.value
但是,这不起作用,因为我遇到了异常:
AttributeError: can't set attribute
这是有道理的,但是做这样的事情的惯用方式是什么?我不只是想使用不同的名称。
解决方案
您正在尝试将其self.value
用作属性的名称,以及用于存储该属性的属性名称。那没有意义;你需要给它一个不同的名字。由于该属性是“私有的”,并且只能通过属性访问,因此您通常希望使用下划线前缀。
换句话说,做与文档property
中的示例完全相同的事情。
当然,if not value:
必须将其更改为通过 访问相同的属性self
,而不是某些具有相同名称的局部变量。
class A:
_value = None
@property
def value(self):
if not self._value:
result = <do some external call>
self._value = result
return self._value
另一种选择是使用为您执行此操作的库。正如 Martijn Pieters 在评论中指出的那样,cached-property
它可以为您提供您想要的东西。它在您可能从未想过的各种边缘情况(例如线程和异步)中经过测试且稳健。它也有很好的文档和可读的源代码,解释了它是如何工作的。
无论如何,为什么这_value = None
是正确的可能不是很明显。
_value = None
在类定义中创建一个名为的类属性_value
,由该类的所有实例共享。
self._value = result
在方法主体中不会更改该类属性,它会创建一个具有相同名称的实例属性。
实例属性影子类属性。也就是说,当您尝试访问and语句self._value
时,它会查找实例属性,如果不存在则回退到类属性。因此,类属性的值作为实例属性的默认值。if
return
None
对于提供默认属性值,这是一个非常常见的习惯用法——但在某些情况下(例如,使用可变值)可能会造成混淆。
做同样事情的另一种方法是通过在您的or方法_value
中设置它来强制实例始终具有一个属性:__new__
__init__
class A:
def __init__(self):
self._value = None
@property
def value(self):
if not self._value:
result = <do some external call>
self._value = result
return self._value
虽然乍一看这有点冗长和复杂(并且需要了解__init__
),但它确实避免了混淆类与实例属性的可能性,因此如果您与新手共享代码,他们更有可能会能够跟随它。
或者,您可以使用getattr
来查看属性是否存在,因此您不需要后备类属性或__init__
,但这通常不是您想要做的。
退后一步,您甚至可以property
使用在第一次查找时替换自身的描述符进行替换——但如果您不知道这意味着什么(即使在阅读了HowTo之后),您可能也不想这样做。
推荐阅读
- amazon-web-services - 当我们在 SQS 上使用 SSE 时,为什么 S3 需要密钥权限?
- python - mplcursors 仅显示 y 坐标
- javascript - Nuxt js custum js文件未加载
- python - Python - 在具有容错性的列表中测量某个值的最长子序列
- c# - Windbg 从 .foreach 值解析变量
- c++ - 我收到以下错误:在抛出 'std::bad_alloc' 的实例后调用终止
- python - /personal_detail/ 处的 IntegrityError
- reactjs - 自定义反应表
“全选”复选框列位置和样式 - swift - 在 Swift 中,如何在嵌套计时器中引用“self”?
- r - 以公里为单位对具有给定分辨率的矢量进行栅格化