A deep analysis of multiple inheritance problems in Python class

Source: Internet
Author: User
Body

The first thing to note is that the Python classes are divided into classic classes and modern classes
The classic class is something before python2.2, but in 2.7 it's still compatible, but in the 3 version, it only admits the new class.
New classes can be used in versions after python2.2

The difference between a classic class and a new class is:

The classic class is not derived from a base class by default, and the new class is derived from the base class by default:

The code is as follows:


# Old Style
Class A ():p

# New Style
Class A (OBEJCT):p

2. In the case of class multiple inheritance, the classic class adopts the principle of left-to-right depth-first matching method. The new class is matched using the C3 algorithm (which is different from the breadth first).

3. The classic class is not called by __mro__ and Instance.mro (), and the new class is there.

Why not use the classic class, to change to the new class

Because multiple inheritance in a classic class can be problematic ... A method query that may result in an inheritance tree bypasses the following parent class:

The code is as follows:


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

D = d ()
D.foo1 ()

According to the rule that the classic class looks in order from left to right, the D class is not available when accessing D.foo1 (). So look up, first find B, there is no, depth first, access a, found Foo1 (), so this time is called a foo1 (), resulting in C rewrite of Foo1 () is bypassed.

So Python introduces the concept of a new class, each of which inherits from object and his matching rules change from depth to C3

C3 algorithm

How does the C3 algorithm do the matching? After discussion in the question and answer section, it boils down to the following:

A core of the C3 algorithm is the merge.

In the merge list, if the first class of the first sequence MRO is in a different sequence and is the first, or no other sequence is present, then the class is removed from the sequence and closed to the list of access orders
For example: (quoting the question Zhuangzebo answer @zhuangzebo)

The code is as follows:


Class A (O):p
Class B (O):p
Class C (O):p
Class D (A, b):p
Class E (C,d):p

First you need to know that the list of O (object) MRO (method resolution Order) is [O,]
So here's the next:

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]

Then there is a special case:
Like what:
Merge (Do,co,c) The first merge is D
Merge (Do,co,c) The first merge is C
It means. When there is a class that appears in the header of the two series (for example, C) This is the case and the class is matched in a sequential fashion only when the head of a sequence (for example, D) is present at the same time.

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 last match is matched in the order of the MRO sequence.

C3 and breadth-first differences:

For example, it is perfectly clear:

The code is as follows:


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

In terms of breadth-first traversal, the MRO sequence F should be [F,c,e,b,d,a]
But C3 is [f,e,d,c,b,a]
It means that you can think of C3 as the intersection of one link to another, and then go deep through the other link, and finally traverse the intersection.

Super and class name access issues for new and classic classes

In the classic class, if you want to access the parent class, it is accessed using the class name.

The code is as follows:


Class A ():
def __init__ (self):
Print "A"
Class B (A):
def __init__ (self):
Print "B"
A.__init__ (self) #python不会默认调用父类的初始化函数的

This looks like there are no three problems, but if the inheritance structure of the class is more complex, it can cause poor maintainability of the code.
So the new class introduced Super this thing ...

The code is as follows:


Class A ():
def __init__ (self):
Print "A"
Class B (A):
def __init__ (self):
Print "B"
Super (B,self). __init__ ()

At this point, there is another question: When a class is multiple inheritance, which class does super access?
Super is actually using the __mro__ sequence to determine which class to access ... is actually the method of invoking a class that follows this class in __mro__.
For example, the sequence is [F,e,d,c,b,a] then the super in F is E,e D.

Super and follow the class name access to the pits brought by mixed use

The code is as follows:


Class A (object):
def __init__ (self):
Print "Enter A"
Print "Leave A"

Class B (object):
def __init__ (self):
Print "Enter B"
Print "Leave B"

Class C (A):
def __init__ (self):
Print "Enter C"
Super (C, self). __init__ ()
Print "Leave C"

Class D (A):
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"

This time the print out is:

The code is as follows:


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

It can be seen that the initialization function of D and a has been messed up two times!
Access by class name is equivalent to the Goto statement before the C language ... Jump, and then use super in order to access: There's a problem.

So the suggestion is either to always use super, or to always use the class name to access

Best implementations:

Avoid multiple inheritance
Super uses consistent
Don't mix classic and modern classes
Check the class hierarchy when calling the parent class

The above is my understanding of the Python class inheritance, I hope to be helpful to everyone

  • 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.