Python super ()

Source: Internet
Author: User

First, the problem of the discovery and proposed

In the Python class method, to invoke a method of the parent class, before Python 2.2, the usual notation is code Snippet 1:

Code Snippet 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

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

That is, use a non-binding class method (a method referenced with the class name), and in the argument list, introduce the object to be bound (self) to achieve the purpose of calling the parent class.

The disadvantage of this is that when the parent class of a subclass changes (such as when the parent class of Class B is changed from A to C), the entire class definition must be traversed, replacing all the class names of the unbound methods, such as code Snippet 2,

Code Snippet 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, this change might be acceptable. But if the amount of code is large, such a modification could be catastrophic.

So, since Python 2.2, Python has added a keyword super to solve this problem. The following is an official document description of Python 2.3:

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, you can rewrite class B as code Snippet 3:

Code Snippet 3:

Class A (object):    # A must is 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, the result is consistent, but only one place to modify the code, to minimize the maintenance of the code, is a good use. So in our development process, the Super keyword is heavily used and has been performing well.

In our impression, for super (b, self). __init__ () is the understanding that super (b, self) first finds the parent of B (that is, Class A), and then converts the object of Class B to the object of Class A (in a way that has not been refined in any way, Ashamed), and then the "converted" Class A object calls its own __init__ function "so, super () actually returns an instance of a parent class, and only the instance can invoke the method without self." Given that there is only a mechanism for specifying subclasses in Super, in a multi-inheritance class definition, we usually keep using a method similar to code Snippet 1.

One day a colleague designed a relatively complex class architecture (let's not care if this class system is designed to be reasonable, just consider this example as a topic), Code Snippet 4:

Code Snippet 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"

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"

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 le Ave F

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 le Ave F

Obviously, the initialization functions of Class A and Class D are called repeatedly 2 times, which is not the result we expect! The result we expect is that at most only the initialization function of Class A is called 2 times-in fact, this is a problem that a multi-inheritance class system must face. We draw the class system of code snippet 4, such as:

Object
| \
| A
| / |
B C D
\   /   |
E |
\   |
F

In our understanding of super, we can see that when invoking the initialization function of Class C, the initialization function of Class A is called, but the initialization function of Class D is actually called. Good one weird problem!

That is, the MRO records a sequence of class types for all the base classes of a class. Review the MRO records and discover that there are 7 elements, and 7 class names are:

F E B C D A Object

This explains why super (C, self) is used in c.__init__. __INIT__ () invokes the initialization function of Class D.???

Let's rewrite code snippet 4 to:

Code Snippet 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 "

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 "

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 invocation of all the parent classes, but also guarantees that the initialization function of each parent class is called only once.

Look at the class structure again:

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

E-1,d-2 is the parent class of F, which represents the class E before, i.e. F (e,d).

So the sequence of initialization can be seen from the class structure diagram: F->e->b-->c----and A

Because C,d has the same parent class, the D is first initialized and then a.

Iii. continuation of the discussion

We re-look at the class system diagram above, if each class as a graph of a node, each from the subclass to the parent of the direct inheritance relationship as a directed edge, then the system diagram will become a directed graph. The order of the MRO can not be found to be exactly a topological sort sequence of the graph.

Thus, we get another result--python is how to deal with multiple inheritance. Traditional object-oriented programming languages (such as C + +), which support multiple inheritance, are implemented by virtual inheritance to implement multiple calls to the constructors of the parent class in multiple inheritance, while Python is handled by the MRO approach.

But this gives us a problem: for the writer who provides the class system, he does not know how the user will use his class system, that is, incorrect follow-up classes may lead to errors in the original class system, and such errors are very covert and difficult to find.

Iv. Summary

1. Super is not a function, it is a class name, like Super (B, self) actually called the Super class initialization function,
produced a Super object;
2. The Super class initialization function does not do anything special, but simply records the class type and the concrete instance;
3. Super (B, self). The invocation of Func is not a Func function that invokes the parent class of the current class;
4. Python's multi-inheritance class ensures that functions of each parent class are called through the MRO method, and that each parent class function
Call only once (if each class uses Super);
5. Mixing super and unbound functions is a risky behavior, which can cause the parent class function that should be called to not call or a
A parent class function is called multiple times.

Python super ()

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.