In-depth analysis of multiple inheritance issues of Python classes

Source: Internet
Author: User
Yesterday, I had a long struggle with the multiple inheritance of the Python class. after consulting a lot of experts, I fully understood it. now I have sorted out the features of the class for future reference, you can also give reference to the following body for those who need it.

First, you must note that Python classes are classified into classic classes and new classes.
The classic class is something before python2.2, but it is still compatible with Python 2.7, but only the new class is recognized in versions later than Python.
New classes can be used in versions later than python2.2.

The difference between classic classes and new classes is:

Classic classes are not derived from a base class by default, while new classes are derived from the base class of object by default:

The code is as follows:


# Old style
Class A (): pass

# New style
Class A (obejct): pass

2. Classic classes use the left-to-right depth priority matching method in multi-inheritance of classes. The new classes use the C3 algorithm (different from the breadth-first algorithm) for matching.

3. Classic classes are called Without _ MRO _ and instance. mro (), while new classes are available.

Why don't you use Classic Classes? you need to replace them with new classes.

There may be some problems with multi-inheritance in the classic class... it may cause the method query in the inheritance tree to bypass the parent class below:

The code is as follows:


Class ():
Def foo1 (self ):
Print ""
Class B ():
Def foo2 (self ):
Pass
Class C ():
Def foo1 (self ):
Print "C"
Class D (B, C ):
Pass

D = D ()
D. foo1 ()

According to the classic class search order from left to right depth priority rules, in the access d. in foo1 (), the Class D does not exist .. in this case, search for B first. if B is not found, the depth is preferred. access A and foo1 () is found. Therefore, foo1 () of A is called at this time (), as a result, the foo1 () of C rewrite is bypassed.

Therefore, python introduces the concept of a new class. each base class inherits from the object and its matching rules also change from depth to C3.

C3 algorithm

How does the C3 algorithm match? after discussing it in the Q & A forum, the reasons are as follows:

One core of the C3 algorithm is merge.

In the merge list, if the first class of the first mro sequence appears in another sequence and is also the first, or no other sequence appears, this class will be deleted from these sequences and merged into the access sequence list.
For example: (zhuangzebo's answer @ zhuangzebo in the reference question)

The code is as follows:


Class A (O): pass
Class B (O): pass
Class C (O): pass
Class D (A, B): pass
Class E (C, D): pass

First, you need to know that the mro (method resolution order) list of O (object) is [O,]
The following is:

The code is as follows:


Mro (A) = [A, O]
Mro (B) = [B, O]
Mro (C) = [C, O]
Mro (D) = [D] + merge (mro (A), mro (B), [A, B])
= [D] + merge ([A, O], [B, O], [A, B])
= [D, A] + merge ([O], [B, O], [B])
= [D, A, B] + merge ([O], [O])
= [D, A, B, O]
Mro (E) = [E] + merge (mro (C), mro (D), [C, D])
= [E] + merge ([C, O], [D, A, B, O], [C, D])
= [E, C] + merge ([O], [D, A, B, O], [D])
= [E, C, D] + merge ([O], [A, B, O])
= [E, C, D, A, B] + merge ([O], [O])
= [E, C, D, A, B, O]

There is another special case:
For example:
Merge (DO, CO, C) first merge is D
Merge (DO, CO, C) first merge is C
That is. when a class appears in the headers of two sequences (such as C), and this class only appears in the same sequence header (such as D, match in sequence.

The access sequence generated by the new class is stored in a read-only list called MRO ..
You can use instance. _ MRO _ or instance. mro () to access

The final match is performed according to the MRO sequence.

Difference between C3 and breadth-first:

The following is an example:

The code is as follows:


Class A (object): pass
Class B (A): pass
Class C (B): pass
Class D (A): pass
Class E (D): pass
Class F (C, E): pass

The MRO sequence of F should be [F, C, E, B, D, A]
But C3 is [F, E, D, C, B, A]
It means that you can use C3 to traverse the intersection of another link in depth on one link, then traverse another link in depth, and finally traverse the intersection.

Super and access by class name for new and classic classes

In the classic class, if you want to access the parent class, you can use the class name to access it ..

The code is as follows:


Class ():
Def _ init _ (self ):
Print ""
Class B ():
Def _ init _ (self ):
Print "B"
A. _ init _ (self) # python does not call the initialization function of the parent class by default.

It seems that there are no three problems, but if the inheritance structure of the class is complicated, it will lead to poor maintainability of the code ..
So the new class introduces the super thing...

The code is as follows:


Class ():
Def _ init _ (self ):
Print ""
Class B ():
Def _ init _ (self ):
Print "B"
Super (B, self). _ init __()

At this time, there is another question: when the class is multi-inheritance, which class does super access?
Super is actually using the _ MRO _ sequence to determine which class to access... it is actually calling the method of a class following this class in _ MRO.
For example, if the sequence is [F, E, D, C, B, A], then super in F is E, and E is D.

Difficulties caused by the hybrid use of super and class name access

The code is as follows:


Class A (object ):
Def _ init _ (self ):
Print "enter"
Print "leave"

Class B (object ):
Def _ init _ (self ):
Print "enter B"
Print "leave B"

Class C ():
Def _ init _ (self ):
Print "enter C"
Super (C, self). _ init __()
Print "leave C"

Class D ():
Def _ init _ (self ):
Print "enter D"
Super (D, self). _ init __()
Print "leave D"
Class E (B, C ):
Def _ init _ (self ):
Print "enter E"
B. _ init _ (self)
C. _ init _ (self)
Print "leave E"

Class F (E, D ):
Def _ init _ (self ):
Print "enter F"
E. _ init _ (self)
D. _ init _ (self)
Print "leave F"

At this time, it is printed as follows:

The code is as follows:


Enter F
Enter E
Enter B
Leave B
Enter C
Enter D
Enter
Leave
Leave D
Leave C
Leave E
Enter D
Enter
Leave
Leave D
Leave F

It can be seen that the initialization functions of D and A are messy twice!
Accessing by class name is equivalent to the GOTO statement before the C language..., and then using super to access in order... there is a problem.

Therefore, we recommend that you always use super or access by class name.

Best practice:

Avoid multiple inheritance
Consistent usage of super
Do not mix classic and new types
Check the class hierarchy when calling the parent class.

The above is my understanding of python class inheritance. I hope it will help you.

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.