Deep analysis of multi-inheritance problem of Python class _python

Source: Internet
Author: User
Tags inheritance

Body

The first thing to be explained is that Python classes are divided into classic classes and new classes.
The classic class is python2.2, but it's still compatible in 2.7, but the version after 3 only admits the new class.
New classes can be used in later versions of 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, whereas a new class is the default derived from the base class of object:

Copy Code code as follows:

# Old Style
Class A ():p

# New Style
Class A (obejct):p

2. The classical class in the class multiple inheritance is the use of the left to right depth precedence principle matching method. And the new class is to use the C3 algorithm (different from the breadth first) to match

3. Classic classes are not called by __mro__ and Instance.mro (), while new classes are available.

Why not use classic class, change to New class

Because there are problems with multiple inheritance in classic classes ... May cause a method query in the inheritance tree to bypass the following parent class:

Copy Code code 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 ()

This class is not available at the time of access to D.foo1 (), in accordance with the rules of the classic class lookup sequence from left to right depth precedence. Then look up, first find B, there is no, depth first, access a, found Foo1 (), so this time the call is a foo1 (), resulting in C rewrite foo1 () is bypassed.

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

C3 algorithm

C3 algorithm is how to do match it. 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 appears in another sequence and is the first, or does not appear in another sequence, the class is removed from the sequence and closed to the Access order list
For example: (Zhuangzebo answer in the reference question @zhuangzebo)

Copy Code code 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 O (object) MRO (method resolution Order) list is [O,]
So the next thing is:

Copy Code code 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]

And then there's a special case:
Like what:
Merge (Do,co,c) first the merge is D
Merge (Do,co,c) first the merge is C
It means. When there is a class that appears in the head of a two sequence (such as C), the case is matched in a sequential fashion when the class is only present at the same time as the head of a sequence (such as D).

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

The difference between C3 and breadth first:

For example, it's completely clear:

Copy Code code 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

According to breadth first traversal, F's MRO sequence should be [F,c,e,b,d,a]
But C3 is [f,e,d,c,b,a]
It means you can think of it as a C3 the intersection of the depth of a link to and another link, then go to the depth to traverse another link, and finally traverse the intersection.

Super of new class and classic class and access problem by class name

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

Copy Code code 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 a class is complex, it can lead to poor code maintainability.
So the new class introduced Super this thing ...

Copy Code code 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 the class is multiple inheritance, which is the Super access class?
Super is actually using the __mro__ sequence to determine which class to access ... is actually the method of calling a class that follows this class in __mro__.
For example, the sequence is [f,e,d,c,b,a] so the super in F is E,e D.

Super and access to mixed use by class name to bring the pits

Copy Code code 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 it is printed:

Copy Code code 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

As you can see, the initialization functions for D and a have 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. It's a problem.

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

Best implementation:

Avoid multiple inheritance
Super uses consistent
Don't mix classic and new classes
When calling the parent class, pay attention to checking the class hierarchy

The above is my understanding of the Python inheritance, I hope to be able to help you

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.