gpt4 book ai didi

python - 为什么这个父类setter调用使用type(self)而不是self?

转载 作者:行者123 更新时间:2023-12-04 08:00:08 25 4
gpt4 key购买 nike

Python @property inheritance the right way解释如何调用父 setter 。

class Number:
def __init__(self):
self._value = None

@property
def value(self):
assert self._value is not None
return self._value

@value.setter
def value(self, new_value):
self._value = new_value


class Integer(Number):
@property
def value(self):
return super().value

@value.setter
def value(self, new_value):
_value = int(new_value)
super(Integer, type(self)).value.fset(self, _value) # <----- OK with using type(self)
# super(Integer, self).value.fset(self, _value) # <----- Assert error with self

i = Integer()
i.value = 1 # cause assertion error with "super(Integer, self)"
print(i.value)

问题

使用 super(Integer, type(self)).value.fset(self, _value)i.value = 1 按预期调用 setter 。

使用 super(Integer, self).value.fset(self, _value)i.value = 1 调用 getter 而不是 setter,因此导致断言错误。

AssertionError                            Traceback (most recent call last)
<ipython-input-8-2c57a07c128d> in <module>
35
36 i = Integer()
---> 37 i.value = 1
38 print(i.value)

<ipython-input-8-2c57a07c128d> in value(self, new_value)
32 _value = int(new_value)
33 #super(Integer, type(self)).value.fset(self, _value)
---> 34 super(Integer, self).value.fset(self, _value)
35
36 i = Integer()

<ipython-input-8-2c57a07c128d> in value(self)
10 @property
11 def value(self):
---> 12 assert self._value is not None
13 return self._value

问题

请帮助理解为什么 super(Integer, self).value.fset(self, _value) 尽管调用了 fset 但会转到 getter 而不是 setter 。阅读文档和文章,在我看来传递对象 self 而不是类型/类 type(self) 是访问绑定(bind)到实例本身的方法的正确方法, 但它不起作用。

super([type[, object-or-type]])

The object-or-type determines the method resolution order to besearched. The search starts from the class right after the type.

For example, if mro of object-or-type is D -> B -> C -> A ->object and the value of type is B, then super() searches C -> A ->object.

The mro attribute of the object-or-type lists the methodresolution search order used by both getattr() and super(). Theattribute is dynamic and can change whenever the inheritance hierarchyis updated.

Supercharge Your Classes With Python super()

In Python 3, the super(Square, self) call is equivalent to theparameterless super() call. The first parameter refers to the subclassSquare, while the second parameter refers to a Square object which, inthis case, is self. You can call super() with other classes as well:

    def surface_area(self):
face_area = super(Square, self).area()
return face_area * 6

def volume(self):
face_area = super(Square, self).area()
return face_area * self.length

What about the second parameter? Remember, this is an object that isan instance of the class used as the first parameter. For an example,isinstance(Cube, Square) must return True.

By including an instantiated object, super() returns a bound method: amethod that is bound to the object, which gives the method theobject’s context such as any instance attributes. If this parameter isnot included, the method returned is just a function, unassociatedwith an object’s context.

最佳答案

super(Integer, self).value.fset(self, _value) 的问题(或更简单的等价物,super().value.fset(self, _value)) 发生在您到达 fset 之前。描述符协议(protocol)参与对一个实例的所有查找,使其通过执行 super(Integer, self).value(或 super().value)简单地调用 getter ).这就是为什么您继承的 setter/getter 首先起作用的原因;它调用了 property 描述符,并获得了它产生的值。

为了绕过描述符协议(protocol)(更准确地说,从实例转移到类级别的调用,其中 property 在类级别场景中没有做任何特殊的事情),您需要执行查找类本身,而不是它的一个实例。 super(Integer, type(self)) 调用 super 的形式返回一个 super 对象绑定(bind)在类级别,而不是实例级别,允许您检索原始描述符本身,而不是调用描述符并获取它产生的值。获得原始描述符后,您可以访问和调用附加到它的 fset 函数。

super 涉及时,这与您遇到的问题相同。如果你有一个 Number 的实例,并且想直接访问 fset 函数(而不是通过赋值隐式调用它),你必须这样做:

num = Number()
type(num).value.fset(num, 1)

因为在做:

num.value.fset(num, 1)

当您检索 num.value 时失败(获取 getter 生成的 None),然后尝试在 上查找 fset

关于python - 为什么这个父类setter调用使用type(self)而不是self?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66512930/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com