Python 让@property只运行一次

Python 让@property只运行一次,python,Python,我举了以下例子: class A: value = None @property def value(self): if not value: result = <do some external call> self.value = result return self.value 这是有道理的,但是像这样做的惯用方式是什么呢?我不只是想用不同的名字 您试图使用self.val

我举了以下例子:

class A:
    value = None
    @property
    def value(self):
        if not value:
            result = <do some external call>
            self.value = result
        return self.value

这是有道理的,但是像这样做的惯用方式是什么呢?我不只是想用不同的名字

您试图使用
self.value
作为属性的名称,以及用于存储该属性的属性的名称。这没有道理;你需要给它一个不同的名字。由于该属性是“private”属性,并且只能通过属性访问,因此通常需要使用下划线前缀

换句话说,执行与中的示例中完全相同的操作

当然,
如果不是值:
必须更改,才能通过
self
访问相同的属性,而不是使用相同名称的局部变量

class A:
    _value = None
    @property
    def value(self):
        if not self._value:
            result = <do some external call>
            self._value = result
        return self._value
虽然乍一看这有点冗长和复杂(需要了解
\uuuu init\uuuu
),但它确实避免了关于类和实例属性的潜在混淆,因此如果您与新手共享代码,他们很可能会遵循它

或者,您可以使用
getattr
查看该属性是否存在,这样您就不需要回退类属性或
\uuuuuu init\uuuuu
,但这通常不是您想要做的



退一步说,您甚至可以用描述符替换
属性
,该描述符在第一次查找时替换自身,但如果您不知道这意味着什么(即使在阅读之后),您可能也不想这样做。

此代码的可能重复没有任何意义。为什么将
value=None
作为类变量放置,却立即用
属性替换它?无法设置属性,因为尚未定义setter。另外,
如果没有值:
会抛出一个
名称错误
,因为
没有定义,所以这个代码不会到达
属性错误
@juanpa.arrivillaga我已经添加了一些解释。另一个选项是使用没有
设置
删除
方法的描述符,因此,您可以简单地设置
self.\uuu dict\uuu['name']=value
,并且在后续访问中不再调用描述符。@MartijnPieters是的,但我不知道是否要尝试向那些在基础知识方面有困难的人解释这一点,我不喜欢给人们魔术般的调用,他们可以复制和粘贴而没有任何理解的希望,也永远无法调试或修改。如果你认为你能解释它,请写一个单独的答案。@abarnert:够公平的;只是想把它也放出来。也要为未来的读者编写,而不仅仅是当前的OP,然后考虑是否可以使非数据描述符选项足够清晰。或者只需简单介绍一下。@MartijnPieters我不知道的
cached_属性
;这似乎确实值得包括在内。但是对于诚实地为未来的读者写作,我认为没有任何一个理解描述符的人会在这个问题中寻找任何东西,而且我不认为在使用“<代码> @属性< /代码>、<代码>私下< /代码>属性等基础知识的长期答案中,尝试教描述符是可行的。(我认为,即使解释类与实例属性,也会推动它……)
class A:
    _value = None
    @property
    def value(self):
        if not self._value:
            result = <do some external call>
            self._value = result
        return self._value
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