title: Why does this parent class setter call use type(self) rather than self?
body: <p><a href="https://gist.github.com/Susensio/979259559e2bebcd0273f1a95d7c1e79" rel="nofollow noreferrer">Python @property inheritance the right way</a> explains how to call the parent setter.</p>
  <pre><code>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) # &lt;----- OK with using type(self)
          # super(Integer, self).value.fset(self, _value)     # &lt;----- Assert error with self
          
  i = Integer()
  i.value = 1             # cause assertion error with &quot;super(Integer, self)&quot;
  print(i.value) 
  </code></pre>
  <h1>Problem</h1>
  <p>With <code>super(Integer, type(self)).value.fset(self, _value)</code> , <code>i.value = 1 </code> invokes the setter as expected.</p>
  <p>With <code>super(Integer, self).value.fset(self, _value)</code>,  <code>i.value = 1 </code> invokes the getter instead of the setter, hence causing the assertion error.</p>
  <pre><code>AssertionError                            Traceback (most recent call last)
  &lt;ipython-input-8-2c57a07c128d&gt; in &lt;module&gt;
       35 
       36 i = Integer()
  ---&gt; 37 i.value = 1
       38 print(i.value)
  
  &lt;ipython-input-8-2c57a07c128d&gt; in value(self, new_value)
       32         _value = int(new_value)
       33         #super(Integer, type(self)).value.fset(self, _value)
  ---&gt; 34         super(Integer, self).value.fset(self, _value)
       35 
       36 i = Integer()
  
  &lt;ipython-input-8-2c57a07c128d&gt; in value(self)
       10     @property
       11     def value(self):
  ---&gt; 12         assert self._value is not None
       13         return self._value
  </code></pre>
  <h1>Question</h1>
  <p>Please help understand why <code>super(Integer, self).value.fset(self, _value)</code> goes to the <strong>getter instead of the setter</strong> although calling <code>fset</code>. Reading the documents and articles, it looks to me passing the object <code>self</code> instead of type/class <code>type(self)</code> is the correct way to access the method bound to the instance itself, but it does not work.</p>
  <p><a href="https://docs.python.org/3/library/functions.html#super" rel="nofollow noreferrer">super([type[, object-or-type]])</a></p>
  <blockquote>
  <p>The object-or-type determines the method resolution order to be
  searched. The search starts from the class right after the type.</p>
  <p>For example, if <strong>mro</strong> of object-or-type is D -&gt; B -&gt; C -&gt; A -&gt;
  object and the value of type is B, then super() searches C -&gt; A -&gt;
  object.</p>
  <p>The <strong>mro</strong> 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.</p>
  </blockquote>
  <p><a href="https://realpython.com/python-super/#a-super-deep-dive" rel="nofollow noreferrer">Supercharge Your Classes With Python super()</a></p>
  <blockquote>
  <p>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:</p>
  <pre><code>    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 
  </code></pre>
  <p>What about <strong>the second parameter</strong>? 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.</p>
  <p><strong>By including an instantiated object, super() returns a bound method: a
  method that is bound to the object</strong>, 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.</p>
  </blockquote>