我有以下示例:
class A:
value = None
@property
def value(self):
if not value:
result = <do some external call>
self.value = result
return self.value
Run Code Online (Sandbox Code Playgroud)
但是,由于我收到异常,因此无效:
AttributeError: can't set attribute
Run Code Online (Sandbox Code Playgroud)
这是有道理的,但做这样的事情的惯用方法是什么?我不只是想使用不同的名字.
您尝试使用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
Run Code Online (Sandbox Code Playgroud)
另一个选择是使用一个为您执行此操作的库.正如Martijn Pieters在评论中指出的那样,cached-property可以准确地给出你想要的东西.并且它在您可能从未想过的各种边缘情况(如线程和asyncio)中经过测试和强大.它还有很好的文档和可读的源代码,它解释了它的工作原理.
无论如何,为什么这_value = None是正确的可能不是很明显.
_value = None在类定义中创建一个名为的类属性_value,由该类的所有实例共享.
self._value = result在方法体中不会更改该类属性,它会创建一个具有相同名称的实例属性.
实例属性阴影类属性.也就是说,当您尝试访问self._value在if和return声明,看起来一个实例属性,那么如果不存在回落到一个类属性.因此,class属性的None值作为实例属性的默认值.
为了提供默认属性值,这是一个非常常见的习惯用法 - 但在某些情况下它可能会令人困惑(例如,使用可变值).
另一种方式做同样的事情是正义的力量的情况下,始终有一个_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
Run Code Online (Sandbox Code Playgroud)
虽然这看起来有点冗长和复杂(并且需要了解__init__),但它确实避免了对类与实例属性混淆的可能性,因此如果您与新手共享代码,则更有可能他们会能够遵循它.
或者,您可以使用getattr查看属性是否存在,因此您不需要回退类属性或__init__,但这通常不是您想要做的.
退一步,你甚至可以property用在第一次查找时替换自己的描述符替换 - 但如果你不知道这意味着什么(即使在阅读了HowTo之后),你可能也不想这样做.
| 归档时间: |
|
| 查看次数: |
128 次 |
| 最近记录: |