A detailed explanation of how the super class works in python

  • 2021-06-29 11:16:23
  • OfStack

super works as follows:


def super(cls, inst):
  mro = inst.__class__.mro()
  return mro[mro.index(cls) + 1]

Among them, cls represents the class, inst represents the instance, and the code above does two things:

Get MRO list for inst Find cls in the current MRO list and return its next class, mro [index + 1]

When you use super (cls, inst), Python searches the MRO list of inst for the next class of cls.

Here's an example:


class A:
  def __init__(self):
    self.n = 2

  def add(self, m):
    print('\n\nself is {0} @A.add'.format(self))
    self.n += m


class B(A):
  def __init__(self):
    self.n = 3

  def add(self, m):
    print('\n\nself is {0} @B.add'.format(self))
    super(B, self).add(m)
    self.n += 3


class C(A):
  def __init__(self):
    self.n = 4

  def add(self, m):
    print('\n\nself is {0} @C.add'.format(self))
    super(C, self).add(m)
    self.n += 4


class D(B, C):
  def __init__(self):
    self.n = 5

  def add(self, m):
    print('\n\nself is {0} @D.add'.format(self))

    print(super(D, self).__self__)
    print(super(D, self).__thisclass__)

    super(D, self).add(m)
    self.n += 5


if __name__ == '__main__':

  print(D.mro())
  d = D()
  d.add(2) #  Equivalent to Yes:  D.add(d, 2)
  print(d.n)

The result is:


[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

<__main__.D object at 0x101ef16d8>


self is <__main__.D object at 0x101ef16d8> @D.add
<__main__.D object at 0x101ef16d8>
<class '__main__.D'>


self is <__main__.D object at 0x101ef16d8> @B.add


self is <__main__.D object at 0x101ef16d8> @C.add


self is <__main__.D object at 0x101ef16d8> @A.add
19

Here are a few details from this result:

print (D.mro()) First prints the mro list of the D class: [ < class '__main__.D' > , < class '__main__.B' > , < class '__main__.C' > , < class '__main__.A' > , < class 'object' > ].This is very understandable.

Then we create an instance of the D class with d = D(): < __main__.D object at 0x101ef16d8 > ;For convenience, let's call this instance object at 0x101ef16d8 "Xiaoming"

When calling up the function d.add(2), self of the add function in the D class was actually object at 0x101ef16d8, a smart classmate just created.

Next, super (D, self) is the next class (class) of class D (class D), class B (class B), in the mro list of object at 0x101ef16d8 and in the smart MRO list.

Notice in the mro list < class '__main__.D' > The next one is < class '__main__.B' >

Every add function prints self is < __main__.D object at 0x101ef16d8 > During the retrospective process, self is always an instance of the D class that was originally created at any level.

Why is that?

Note print (super (D, self). uself_u)Output returned by that line: < __main__.D object at 0x101ef16d8 > .

Oh oh?!Isn't this fucking Xiao Ming?

That is, although super () finds the B class and calls the add () function of the B class, its self is still the first instance of the D class (our classmate Xiaoming) to be created, and when it calls the add () function, it still passes such an self to the class B's add () function.

Our "Xiao Ming" is then transported up once to the add() function at each level, so that what is printed at each level is:

self is <__main__.D object at 0x101ef16d8> 或者说: self is 小明


Related articles: