Go deep into super and see how Python solves diamond succession challenges

Source: Internet
Author: User

1. Python inheritance and invoking the parent class member

The Python subclass calls the parent class member in 2 ways, namely the normal method and the Super method

Suppose base is a base class

class Base (object):     def __init__ (self):            Print "Base Init"

The common method is as follows

class Leaf (Base):        def __init__ (self):              Base. __init__ (self)               Print "Leaf Init"

The Super method is as follows

class Leaf (Base):        def __init__ (self):              super (Leaf, self). __init__ ()              print "Leaf init"

In the simple scenario above, the two methods have the same effect:

>>> leaf = leaf ()

Base Init

Leaf Init

2. Problems with diamond succession

When we came to the diamond to inherit the scene, we encountered a problem:

If we still call the parent class member using the normal method, the code is as follows:

classBase (object):def __init__(self):Print"Base Init"classMedium1 (Base):def __init__(self): Base.__init__(self)Print"MEDIUM1 Init"classMedium2 (Base):def __init__(self): Base.__init__(self)Print"Medium2 Init"classLeaf (MEDIUM1, Medium2):def __init__(self): Medium1.__init__(self) Medium2.__init__(self)Print"Leaf Init"

When we generate the leaf object, the result is as follows:

>>> leaf = leaf ()

Base Init

MEDIUM1 Init

Base Init

MEDIUM2 Init

Leaf Init

You can see that base has been initialized two times ! This is due to the fact that Medium1 and Medium2 each called base initialization functions.

3. Solutions for each language

In diamond inheritance, it is a very difficult problem for the parent class to be initialized multiple times, so let's look at how the other languages solve the problem:

3.1. C + +

C + + uses virtual inheritance to solve diamond inheritance problems.

Medium1 and Medium2 virtual inherit base. When a leaf object is generated, MEDIUM1 and Medium2 do not automatically invoke the constructor of the virtual base class base, and the constructor of base is called explicitly by the Leaf's constructor.

3.2. Java

Java prohibits the use of multiple inheritance.

Java uses a single inheritance + interface implementation to replace multiple inheritance, avoiding the problems of diamond inheritance.

3.3. Ruby

Ruby prohibits the use of multiple inheritance.

Ruby, like Java, supports only single inheritance, but it differs from Java in the alternative to multiple inheritance. Ruby uses mixin as an alternative, mixin into other modules in the current class, to achieve the assembly effect of the code.

3.4. Python

Python, like C + +, supports syntax for multiple inheritance. But Python's approach is completely different from C + +, and Python uses super

We'll rewrite the diamond in chapter 2nd with Super, and look at the output.

classBase (object):def __init__(self):Print"Base Init"classMedium1 (Base):def __init__(self): Super (MEDIUM1, self).__init__()              Print"MEDIUM1 Init"classMedium2 (Base):def __init__(self): Super (Medium2, self).__init__()              Print"Medium2 Init"classLeaf (MEDIUM1, Medium2):def __init__(self): Super (Leaf, self).__init__()              Print"Leaf Init"

We generate leaf objects:

>>> leaf = leaf ()

Base Init

MEDIUM2 Init

MEDIUM1 Init

Leaf Init

You can see that the entire initialization process is in line with our expectations, and base has been initialized only 1 times. And it's important that the super method doesn't write extra code or introduce additional concepts when compared to the original normal notation.

4. Super Kernel: MRO

To understand the super principle, we need to understand the MRO first. MRO is the abbreviation for method resolution order, which indicates the order of member resolution in the class inheritance system.

In Python, each class has a class method for the MRO. Let's take a look at what the leaf MRO looks like in diamond succession:

>>> Leaf.mro ()

[<class ' __main__. Leaf ', <class ' __main__. Medium1 ';, <class ' __main__. Medium2 ';, <class ' __main__. Base ';, <type ' object ';]

You can see that the MRO method returns a list of ancestor classes. Each ancestor of the leaf appears once, which is the order in which super finds members in the parent class.

By Mro,python, the multi-inheritance graph structure is cleverly transformed into the order structure of the list. Super in the inheritance system in the upward search process, into the MRO in the right linear lookup process, any class will only be processed once.

In this way, Python solves the 2 major challenges of multiple inheritance:

1. Find the order problem. From the Leaf's MRO order, it can be seen that if the leaf class accesses the parent class members through Super, then the members of the MEDIUM1 will be first accessed before Medium2. If both MEDIUM1 and Medium2 are not found, then finally to the base to find.

2. Multiple initialization problems with diamond inheritance. In the MRO list, the base class appears only once. In fact, any class will only appear once in the MRO list. This ensures that the method of any ancestor class is executed only once during super-up invocation.

As for the MRO generation algorithm, you can refer to this article wiki:https://en.wikipedia.org/wiki/c3_linearization

5. Specific uses of super

Let's first look at the super document in Python

>>> Help (Super)

Help on Class super in module __builtin__:

Class Super (object)

| Super (type, obj), bound Super object; Requires Isinstance (obj, type)

| Super (Type)-Unbound Super Object

| Super (Type, type2), bound Super object; Requires Issubclass (type2, type)

Light literally, this is one of the most vague help documents in Python. Even some of the terminology is misused. So how is that super supposed to work, and we're going to focus on the 1th and 3rd uses of super?

5.1. Super (type, obj)

When we write this super in the __init__ of the Leaf:

class Leaf (MEDIUM1, Medium2):        def __init__ (self):              super (Leaf, self). __init__ ()              print "Leaf init"

Super (Leaf, self). __init__ () means that:

    1. Get the MRO of the self-owned class, which is [Leaf, Medium1, Medium2, Base]
    2. Starting with a class on the right side of the leaf in the MRO, look for the __init__ function in turn. This is the beginning of the MEDIUM1 search.
    3. Once found, bind the found __init__ function to the Self object and return

As you can see from this execution process, if we do not want to invoke MEDIUM1 's __init__ and want to invoke Medium2 's __init__, then super should be written as: Super (MEDIUM1, self) __init__ ()

5.2. Super (type, type2)

When we write super-class methods in the leaf:

class Leaf (MEDIUM1, Medium2):        def __new__ (CLS):               = Super (Leaf, CLS). __new__ (CLS)               Print "Leaf new"               return obj

The super (Leaf, CLS). __new__ (CLS) means that:

    1. Get MRO for this class of CLS, also [Leaf, Medium1, Medium2, Base]
    2. Start with a class on the right side of the leaf in the MRO, looking for the __new__ function in turn
    3. Once found, returns the " unbound " __new__ function

Because a non-binding function object is returned, the first argument of the function cannot be omitted when called. This is also why you need to pass in the parameter CLS when calling __new__ here

Similarly, if we want to start looking at a certain MRO location, we just need to modify the first parameter of super.

6. Summary

At this point, we explain the usage and principles related to super, and summarize what we have said:

    1. There are 2 ways to call a parent member of Python: Normal method, Super method
    2. In the case of diamond inheritance, the common method encounters the two initialization of the base class.
    3. This paper describes the solution to this problem in other languages, and shows that Python uses super to solve this problem.
    4. Before you talk about super specific usage, talk about Super kernel: the knowledge and principles of MRO
    5. Explains the super two main usage and principle

Tags: python, super, MRO, multiple inheritance

Go deep into super and see how Python solves diamond succession challenges

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.