6

How does Python's super() work with multiple inheritance?

I was looking at the above question/answers and made myself really confused

 53 class First(object):
 54     def __init__(self):
 55         print "first"
 56
 57 class Second(First):
 58     def __init__(self):
 59         super(Second, self).__init__()
 60         print "second"
 61
 62 class Third(First):
 63     def __init__(self):
 64         print "third"
 65
 66 class Fourth(Second, Third):
 67     def __init__(self):
 68         super(Fourth, self).__init__()
 69         print "thats it"

Fourth()
third
second
thats it

 53 class First(object):
 54     def __init__(self):
 55         print "first"
 56
 57 class Second(First):
 58     def __init__(self):
 59         #super(Second, self).__init__()         <---- commented out
 60         print "second"
 61
 62 class Third(First):
 63     def __init__(self):
 64         print "third"
 65
 66 class Fourth(Second, Third):
 67     def __init__(self):
 68         super(Fourth, self).__init__()
 69         print "thats it"

Fourth()
second
thats it

Could someone explain to me what's happening behind the scene in regards to why the top prints "third" and the bottom one doesn't?

I feel like there is some sort of order/sequence that's happening behind the scene that I am not seeing.

-- Fourth.mro

commented out super in Second
(, , , , )

super in Second
(, , , , )

Community
  • 1
  • 1
ealeon
  • 12,074
  • 24
  • 92
  • 173
  • maybe a duplicate of [How does Python's super() work with multiple inheritance?](http://stackoverflow.com/q/3277367/832621)? – Saullo G. P. Castro Oct 14 '13 at 17:16
  • 4
    @SaulloCastro but thats the question that I linked to... – ealeon Oct 14 '13 at 17:19
  • @ealeon Look at `Fourth.__mro__`, that's the order `super()` follows. – Ashwini Chaudhary Oct 14 '13 at 17:24
  • @George The OP was saying he didn't understand how the explanation in the linked question would apply to this situation. – Asad Saeeduddin Oct 14 '13 at 17:24
  • I will vote to reopen your question after editing it a little bit since the title misleads us to think it is a duplicate... – Saullo G. P. Castro Oct 14 '13 at 17:24
  • 2
    @hcwhsa yes but __mro__ is the same regardless whether Second has super() or not? how does something that's in Second affects whether Third gets invoked or not? – ealeon Oct 14 '13 at 17:31
  • 1
    @ealeon `super()` call in `Second` invokes next item in MRO, not super of `Second`. That's how Mixins work. Read: http://rhettinger.wordpress.com/2011/05/26/super-considered-super/ – Ashwini Chaudhary Oct 14 '13 at 17:34
  • @hcwhsa so desipte its __mro__ being the same, super() call the next item in MRO which is Third, whereas without super, the next item in MRO would not be called and hence with super, third gets invoked. Okay this part makes sense. So, this is saying that not all items in MRO gets invoked? And if i add super in Third, First will get invoked since its the next item in MRO. – ealeon Oct 14 '13 at 17:41
  • But even if Third has super, it will be not called if Second does not have super since Third will never be invoked... hmm.. – ealeon Oct 14 '13 at 17:42

2 Answers2

5

super doesn't actually call the super class. It calls the next method according to the Method Resolution Order (MRO). It looks like the MRO for your example classes is as follows:

Fourth
Second
Third
First

That is, using super from Fourth gets you a method on Second. Using super from Second gets you a method on Third. etc.

In the first example:

  1. Fourth.__init__ is called.
  2. Fourth.__init__ calls Second.__init__ via super.
  3. Second.__init__ calls Third.__init__ via super.
  4. Third.__init__ prints "third"
  5. Second.__init__ prints "second"
  6. Fourth.__init__ prints "that's it".

In the second example:

  1. Fourth.__init__ is called.
  2. Fourth.__init__ calls Second.__init__ via super.
  3. Second.__init__ prints "second"
  4. Fourth.__init__ prints "that's it".

So, yes, changing a super call in Second changes whether something on Third is called, even though Third is not a super class of Second. This is indeed confusing. I recommend reading "Python's Super is nifty, but you can't use it". That's the explanation I read that got the above to make sense to me.

Claudiu
  • 224,032
  • 165
  • 485
  • 680
4

The MRO is not a nested hierarchy. It is a flat list that obeys a set of constraints, namely that each class must precede its base classes, and those base classes must exist in the same order relative to each other as they are mentioned in the subclass declaration.

By printing Fourth.__mro__, we can see the MRO in your examples is:

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

Each call to super that is set off will call the next method in the MRO. You can think of the number of super calls as the zero indexed "depth" into the MRO to which you will descend.

Since there are two calls to super in the first snippet, Second.__init__ and Third.__init__ are called (in addition, of course, to the immediate class' init method). Similarly, in the second snippet you have a single call to super, which means only Second.__init__ will be called.

Asad Saeeduddin
  • 46,193
  • 6
  • 90
  • 139