Python @属性 与其返回的字段相同的id

Python @property same id as field returned by it

我制作了这个简单的片段以更好地理解属性:

class foo:
def __init__(self, val):
    self.val = val

@property
def val(self):
    return self._val

@val.setter
def val(self, value):
    if value < 0:
        raise ValueError("Value has to be larger than 0")
    else:
        self._val = value

  
f1 = foo(2)
print(id(f1._val) == id(f1.val)) #print true

现在我比写代码之前更不理解了。为什么 f1._valf1.val 是同一个对象?是在后台施展的魔法吗?另外,为什么 type(f1.val)int 而它是 function

另一件事是我虽然将两个 val 函数(一个由 [=20= 修饰,第二个由 @val.setter 修饰)更改为 return self.val 而不是 return self._val .尝试实例化对象时,我得到:

RecursionError: maximum recursion depth exceeded in comparison

很明显,我 return 指向函数的指针(不确定指针在这种情况下是否正确?)没有条件。但是在这里,即使 self._valself.val 是同一个对象,我的第一个片段如何工作得很好?

How is it, that both f1._val and f1.val are the same object?

因为您在代码中将它们设置为同一个对象。你取你的值,在本例中为 2 并将其分配给 self.valself._val

你所做的相当于

a = 2

b = 2

a == b

True

Also, why type(f1.val) is int when it is a function?

使用 @property 装饰器时,该方法不再可调用。你几乎可以把它想象成一个属性。

在您的示例中,val3.3.2.2. Implementing Descriptors 中描述的描述符。使用描述符,对变量的访问被替换为对其 __get____set____delete__ 方法的调用。 property 函数是创建描述符的快捷方式。由于“属性”和“描述符”是同一个东西,我不知道为什么使用两个不同的名称。

@property
def val(self):
    return self._val

val 绑定到一个对象,其 __get__ 执行函数体。它获取局部变量 _val.

@val.setter
def val(self, value):
    if value < 0:
        raise ValueError("Value has to be larger than 0")
    else:
        self._val = value

绑定到 val 的对象已更新,以便其 __set__ 执行函数体,设置 _val.

当python执行f1.val时,它得到“val”引用的对象,但在returning之前,它检查对象是否有__get__ .如果是这样,它不会 returning 对象,而是调用 __get__ 并使用它的 return。在你的例子中,“_val”是 returned,所以它们自然是相等的。

如果您更改 属性 函数以获取“val”而不是“_val”,python 仍遵循相同的规则。 “val”是一个描述符,因此它的 __get__ 被调用,它试图再次获取“val”,但它是一个描述符......等等。