Coder Perfect

With multiple inheritance, how does Python’s super() work?

Problem

I’m quite new to Python object-oriented programming, and I’m having problems grasping the super() method (new style classes), particularly when it comes to multiple inheritance.

If you have something like this, for example:

class First(object):
    def __init__(self):
        print "first"

class Second(object):
    def __init__(self):
        print "second"

class Third(First, Second):
    def __init__(self):
        super(Third, self).__init__()
        print "that's it"

What I’m not sure about is whether or not the Third() class will inherit both constructor methods. If so, which one will be executed using super() and why?

What if you wish to take over the other? I’m guessing it has something to do with the order in which Python methods are resolved (MRO).

Asked by Callisto

Solution #1

Guido explains this in his blog post Method Resolution Order in a good bit of detail (including two earlier attempts).

Third(), in your case, will call First. __init__. Python searches the parents of the class from left to right for each attribute. We’re looking for __init__ in this situation. As a result, if you declare

class Third(First, Second):
    ...

Python will start by looking at First, and, if First doesn’t have the attribute, then it will look at Second.

When inheritance crosses tracks, the problem becomes more complicated (for example if First inherited from Second). For further information, see the link above, but in a nutshell, Python will try to keep the order in which each class appears on the inheritance list, starting with the child class.

As an example, if you had:

class First(object):
    def __init__(self):
        print "first"

class Second(First):
    def __init__(self):
        print "second"

class Third(First):
    def __init__(self):
        print "third"

class Fourth(Second, Third):
    def __init__(self):
        super(Fourth, self).__init__()
        print "that's it"

the MRO would be [Fourth, Second, Third, First].

By the way, if Python can’t discover a logical method resolution order, it’ll throw an exception rather than fall back to unexpected behavior.

An unclear MRO is as follows:

class First(object):
    def __init__(self):
        print "first"

class Second(First):
    def __init__(self):
        print "second"

class Third(First, Second):
    def __init__(self):
        print "third"

Is the MRO for Third [First, Second] or [Second, First]? Python will raise an error if there is no evident expectation:

TypeError: Error when calling the metaclass bases
    Cannot create a consistent method resolution order (MRO) for bases Second, First

Why are there no super() calls in the examples above? The purpose of the examples is to demonstrate how the MRO is built. They are not intended to print “first\nsecond\third” or whatever. You can – and should, of course, play around with the example, add super() calls, see what happens, and gain a deeper understanding of Python’s inheritance model. But my goal here is to keep it simple and show how the MRO is built. And it is built as I explained:

>>> Fourth.__mro__
(<class '__main__.Fourth'>,
 <class '__main__.Second'>, <class '__main__.Third'>,
 <class '__main__.First'>,
 <type 'object'>)

Answered by rbp

Solution #2

Your code, as well as the other responses, are all flawed. They are missing the super() calls that are essential for cooperative subclassing to work in the first two classes.

Here is a fixed version of the code:

class First(object):
    def __init__(self):
        super(First, self).__init__()
        print("first")

class Second(object):
    def __init__(self):
        super(Second, self).__init__()
        print("second")

class Third(First, Second):
    def __init__(self):
        super(Third, self).__init__()
        print("third")

The super() call finds the next method in the MRO at each step, which is why First and Second have to have it too, otherwise execution stops at the end of Second. __init__().

What I get is this:

>>> Third()
second
first
third

Answered by lifeless

Solution #3

I wanted to expand on the response a little because I wasn’t sure how to utilize super() in a multiple inheritance hierarchy in Python when I first started reading about it.

What you need to know is that super(MyClass, self). init () gives the next init method in the context of the entire inheritance tree, according to the employed Method Resolution Ordering (MRO) methodology.

This final section is critical to comprehend. Consider the following scenario once more:

#!/usr/bin/env python2

class First(object):
  def __init__(self):
    print "First(): entering"
    super(First, self).__init__()
    print "First(): exiting"

class Second(object):
  def __init__(self):
    print "Second(): entering"
    super(Second, self).__init__()
    print "Second(): exiting"

class Third(First, Second):
  def __init__(self):
    print "Third(): entering"
    super(Third, self).__init__()
    print "Third(): exiting"

According to this article about Method Resolution Order by Guido van Rossum, the order to resolve __init__ is calculated (before Python 2.3) using a “depth-first left-to-right traversal” :

Third --> First --> object --> Second --> object

We get the following after deleting all duplicates save the last one:

Third --> First --> Second --> object

So, let’s see what happens when we create a Third class instance, e.g. x = Third ().

This explains why using Third() produces the following:

Third(): entering
First(): entering
Second(): entering
Second(): exiting
First(): exiting
Third(): exiting

From Python 2.3 onwards, the MRO technique has been modified to perform well in complex cases, but I believe that using “depth-first left-to-right traversal” + “removing duplicates except for the last” still works in most cases (please comment if this is not the case). Make sure to read Guido’s blog article!

Answered by Visionscaper

Solution #4

The Diamond Problem is described on the page, and in short, Python will call the superclass’s methods from left to right.

Answered by monoceres

Solution #5

Although this isn’t a direct response to the super() question, I believe it is important enough to discuss.

There’s also a way to call each inherited class directly:


class First(object):
    def __init__(self):
        print '1'

class Second(object):
    def __init__(self):
        print '2'

class Third(First, Second):
    def __init__(self):
        Second.__init__(self)

You’ll have to call each manually if you do it this way, as I’m very sure First’s __init__() won’t be called.

Answered by Seaux

Post is based on https://stackoverflow.com/questions/3277367/how-does-pythons-super-work-with-multiple-inheritance