Python @property inheritance the right way explains how to call the parent 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)
Problem
With super(Integer, type(self)).value.fset(self, _value)
, i.value = 1
invokes the setter as expected.
With super(Integer, self).value.fset(self, _value)
, i.value = 1
invokes the getter instead of the setter, hence causing the assertion error.
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
Question
Please help understand why super(Integer, self).value.fset(self, _value)
goes to the getter instead of the setter although calling fset
. Reading the documents and articles, it looks to me passing the object self
instead of type/class type(self)
is the correct way to access the method bound to the instance itself, but it does not work.
super([type[, object-or-type]])
The object-or-type determines the method resolution order to be searched. 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 method resolution search order used by both getattr() and super(). The attribute is dynamic and can change whenever the inheritance hierarchy is updated.
Supercharge Your Classes With Python super()
In Python 3, the super(Square, self) call is equivalent to the parameterless super() call. The first parameter refers to the subclass Square, while the second parameter refers to a Square object which, in this 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 is an 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: a method that is bound to the object, which gives the method the object’s context such as any instance attributes. If this parameter is not included, the method returned is just a function, unassociated with an object’s context.