Reprint super you don't know

http://funhacks.net/2016/11/09/super/

 

In class inheritance, if you redefine a method, the method will override the method of the same name of the parent class, but sometimes, we want to implement the function of the parent class at the same time. At this time, we need to call the method of the parent class. This is achieved by using super, for example:

1 class Animal(object):
2     def __init__(self, name):
3         self.name = name
4     def greet(self):
5         print 'Hello, I am %s.' % self.name
6 class Dog(Animal):
7     def greet(self):
8         super(Dog, self).greet()   # Python3 可使用 super().greet()
9         print 'WangWang...'

In the above, Animal is the parent class, and Dog is the subclass. We redefine the greet method in the Dog class. In order to realize the functions of the parent class at the same time, we call the method of the parent class. See the following usage:

>>> dog = Dog('dog')

>>> dog.greet()

Hello, I am dog.

Wang Wang..

 

One of the most common uses of super can be said to call the initialization method of the superclass in the subclass, for example:

 

1 class Base(object):
2     def __init__(self, a, b):
3         self.a = a
4         self.b = b
5 class A(Base):
6     def __init__(self, a, b, c):
7         super(A, self).__init__(a, b)  # Python3 可使用 super().__init__(a, b)
8         self.c = c

deep into super()

After reading the above use, you may think that the use of super is very simple, nothing more than getting the parent class and calling the method of the parent class. In fact, in the above case, the class obtained by super happens to be the parent class, but in other cases, it is not necessarily so. In fact, super has no substantial relationship with the parent class.

 

Let's look at a slightly more complex example involving multiple inheritance, with the following code:

 

class Base(object):
    def __init__(self):
        print "enter Base"
        print "leave Base"
class A(Base):
    def __init__(self):
        print "enter A"
        super(A, self).__init__()
        print "leave A"
class B(Base):
    def __init__(self):
        print "enter B"
        super(B, self).__init__()
        print "leave B"
class C(A, B):
    def __init__(self):
        print "enter C"
        super(C, self).__init__()
        print "leave C"

Among them, Base is the parent class, A, B inherit from Base, C inherits from A, B, their inheritance relationship is as follows:

 

Base

  /  \

 /    \

A      B

 \    /

  \  /

   C

Now, let's look at using:

>>> c = C()

enter C

enter A

enter B

enter Base

leave Base

leave B

leave A

leave C

If you think that super stands for "calling the method of the parent class", then you may be wondering why the next sentence of enter A is not enter Base but enter B. The reason is that super has no substantial relationship with the parent class, now let's understand how super works.

 

MRO list

In fact, for each class you define, Python will calculate a method resolution order (Method Resolution Order, MRO) list, which represents the order of class inheritance, we can use the following method to get a MRO list of a class:

>>> C.mro()   # or C.__mro__ or C().__class__.mro()

[__main__.C, __main__.A, __main__.B, __main__.Base, object]

How is the order of this MRO list determined? It is implemented through a C3 linearization algorithm

super principle

super works like this:

 

def super(cls, inst):

    mro = inst.__class__.mro()

    return mro[mro.index(cls) + 1]

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

 

Get the MRO list of inst

Find the index of cls in the current MRO list, and return its next class, which is mro[index + 1]

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

 

Now, let's go back to the previous example.

 

First look at the __init__ method of class C:

 

super(C, self).__init__()

Here self is the current instance of C, and the result of self.class.mro() is:

 

[__main__.C, __main__.A, __main__.B, __main__.Base, object]

It can be seen that the next class of C is A, so it jumps to the __init__ of A, then it will print out enter A, and execute the following line of code:

 

super(A, self).__init__()

Note that self here is also an instance of the current C, the MRO list is the same as above, search for the next class of A in MRO, and find that it is B, so, jump to the __init__ of B, then enter B will be printed, instead of enter Base.

 

The whole process is relatively clear, the key is to understand how super works, rather than taking it for granted that super calls the method of the parent class.

 

summary

In fact, super has no substantive relationship with the parent class.

super(cls, inst) gets the next class of cls in the MRO list of inst

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324977325&siteId=291194637