Python super ()

Source: Internet
Author: User

I. Problem Discovery and Proposal

In the method of a python class, to call a method of the parent class, before Python 2.2, the usual method is as follows:

Code Segment 1:

class A:  def __init__(self):   print "enter A"   print "leave A" class B(A):  def __init__(self):   print "enter B"   A.__init__(self)   print "leave B" >>> b = B() enter B enter A leave A leave B

View code

 

That is, use non-bound class methods (Methods referenced by class names), and introduce the objects to be bound (Self) in the parameter list to call the parent class.

The disadvantage is that when the parent class of a subclass changes (for example, when the parent class of Class B changes from A to C), the entire class definition must be traversed, replace all the class names of non-bound methods, such as code snippet 2,

Code Segment 2:

class B(C):    # A --> C  def __init__(self):   print "enter B"   C.__init__(self) # A --> C   print "leave B"

If the code is simple, such changes may be acceptable. However, if the code volume is large, such modifications may be disastrous.

Therefore, since Python 2.2, Python has added a keyword "super" to solve this problem. The official documentation for python 2.3 is as follows:

Super (type [, object-or-type])

Return the superclass of type. If the second argument is omitted the super object
Returned is unbound. If the second argument is an object, isinstance (OBJ, type)
Must be true. If the second argument is a type, issubclass (type2, type) must be
True. Super () only works for new-style classes.

A typical use for calling a cooperative superclass method is:

Class C (B ):
Def meth (self, ARG ):
Super (C, self). Meth (ARG)

New in version 2.2.

From the description, we can rewrite Class B as code Segment 3:

Code Segment 3:

class A(object):    # A must be new-style class  def __init__(self):   print "enter A"   print "leave A"class B(C):     # A --> C  def __init__(self):   print "enter B"   super(B, self).__init__()   print "leave B"

Try to execute the same code above, and the results are consistent, but there is only one modified code, which minimizes the maintenance of the Code, which is a good usage. Therefore, in our development process, the super keyword is widely used and has always performed well.

In our impression, for super (B, self ). _ init _ () is as follows: Super (B, self) first finds the parent class of B (Class ), then, convert the self object of Class B to the object of Class A (in some way, I have never studied what the method is ), the converted Class A object then calls its own _ init _ function. Considering that super only specifies the subclass mechanism, in the multi-inheritance class definition, we usually retain the method similar to code segment 1.

One day, a colleague designed a relatively complex class architecture (we should not care whether the class system design is reasonable, but just take this example as a question to study ), code example 4:

Code segment 4:

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"

View code

F = f () Result:

 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

View code

Obviously, the initialization functions of Class A and Class D are repeatedly called twice, which is not the expected result! The expected result is that only the initialization function of Class A is called twice. In fact, this is a problem that must be faced by the multi-inheritance class system. We will draw out the class system of code segment 4, such:

Object
| \
|
|/|
B c d
\/|
E |
\ |
F

According to our understanding of super, we can see that when calling Class C's initialization function, we should call class A's initialization function, but actually called Class D's initialization function. A strange problem!

That is to say, Mro records the sequence of class types of all base classes of a class. Check the Mro records and find that there are 7 elements and the seven class names are:

F e B c d A Object

This explains why super (C, self). _ init _ () is used in C. _ init _ to call the initialization function of class D. ???

We rewrite code segment 4:

Code segment 9:

class A(object):  def __init__(self):   print "enter A"   super(A, self).__init__()  # new   print "leave A" class B(object):  def __init__(self):   print "enter B"   super(B, self).__init__()  # new   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"   super(E, self).__init__()  # change   print "leave E" class F(E, D):  def __init__(self):   print "enter F"   super(F, self).__init__()  # change   print "leave F"

View code

F = f () Result:

 enter F enter E enter B enter C enter D enter A leave A leave D leave C leave B leave E leave F

Obviously, the initialization of F not only completes the call of all parent classes, but also ensures that the initialization function of each parent class is called only once.

Let's look at the class structure:

    object     /   \    /      A   |     /   \  B-1  C-2   D-2    \   /    /     E-1    /        \  /          F

E-1, The D-2 is the parent class of F, which represents Class E in front, that is, F (E, D ).

The initialization sequence can be seen from the class structure diagram: F-> E-> B --> C --> d -->

Because c and d have the same parent class, they initialize d before.

Iii. Continuation Discussion

Let's re-look at the class system diagram above. If we look at each class as a node and the direct inheritance relationship between each subclass and its parent class as a directed edge, then the system diagram will become a directed graph. It cannot be found that the Mro sequence is just a topological sorting sequence of the directed graph.

In this way, we get another result: How does Python process multi-inheritance. The traditional object-oriented programming language (such as C ++) that supports multi-inheritance is a problem in which the constructor of the parent class in Multi-inheritance is called multiple times through virtual inheritance, python is processed by Mro.

But this gives us a difficult problem: for the compiler who provides the class system, he does not know how the user will use his class system. That is to say, the following classes are incorrect, it may lead to errors of the original class system, and such errors are very concealed and difficult to be found.

Iv. Summary

1. Super is not a function. It is a class name. For example, super (B, self) actually calls the initialization function of the super class,
Generates a super object;
2. The super class initialization function does not perform any special operations, but simply records the class type and specific instance;
3. The call of super (B, self). func is not used to call the func function of the parent class of the current class;
4. The multiple inheritance classes of Python use Mro to ensure that the functions of each parent class are called one by one, and each parent class function is also guaranteed.
Only one call (if each class uses super );
5. mixing super classes and unbound functions is a dangerous action, which may cause the parent class function to be called not to be called or
Parent functions are called multiple times.

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.