【问题标题】:Python @property same id as field returned by itPython @property 与它返回的字段相同的 id
【发布时间】:2020-10-14 20:47:34
【问题描述】:

我做了这个简单的 sn-p 来更好地理解属性:

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 函数(一个由@property 装饰,第二个由@val.setter 装饰)更改为return self.val 而不是return self._val。当试图实例化我得到的对象时:

RecursionError: maximum recursion depth exceeded in comparison

当我毫无条件地返回指向函数的指针(不确定指针在这种情况下是否正确?)时,什么是非常明显的。但是在这里,即使 self._valself.val 都是同一个对象,我的第一个 sn-p 是如何工作的?

【问题讨论】:

  • "f1._valf1.val 是同一个对象,这是怎么回事?"因为val 属性getter 只是返回self._val... 我不确定你不明白什么。当您执行f1.val调用 getter 并评估该值时,您了解吗?
  • foo.val 不再是函数。这是一个propertyproperty 对象实现descriptor protocol。基本上,某个类的描述符MyClass.some_desriptor 可以定义__get____set____delete__ 方法。当您创建实例时,myinstance = MyClass() 将分别为 myinstance.my_descriptormyinstance.my_desriptor = foodel myinstance.my_descriptor 调用描述符 __get____set____delete__ 方法
  • 当类中定义了另一个方法时,例如func 返回一个 int,我会以同样的方式实例化类,type(f1.func) 是方法,而 type(f1.func()) 是 int。对于我,这说得通。那么type(f1.val())也应该是一个int,而type(f1.val)应该是我理解的一种方法(但是我可能错了)
  • *它不是一个方法,它是一个property 对象。你明白@property 在做什么吗?你知道什么是装饰器吗?我在上面解释了描述符,property 也是一个装饰器,但这主要是句法糖。基本上@property def val(self): ... 等价于def val(self): ... 然后val = property(val)。所以类val属性不再是函数/方法。这是一个property 描述符。注意,函数也是描述符,这就是它们“神奇地”提供实例作为第一个参数的方式
  • 是的,是的,谢谢。我的评论是在网页刷新之前发布的,我看到了你的第二条评论。

标签: python properties


【解决方案1】:

在您的示例中,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”引用的对象,但在返回之前,它会检查对象是否有__get__。如果是这样,它不会返回对象,而是调用__get__ 并使用它的返回值。在您的情况下,返回“_val”,因此它们自然是相等的。

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

【讨论】:

    【解决方案2】:

    为什么 f1._val 和 f1.val 是同一个对象?

    因为您在代码中将它们设置为相同的对象。你把你的价值,在这种情况下2 分配给self.valself._val

    你所做的相当于

    a = 2

    b = 2

    a == b

    True

    另外,为什么 type(f1.val) 是函数时是 int?

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-19
      • 2020-05-25
      • 2017-02-09
      • 1970-01-01
      • 2014-01-30
      • 1970-01-01
      • 2015-11-05
      相关资源
      最近更新 更多