Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use super to initialize all the parents when using multiple inheritance

Tags:

python

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
(, , , , )

like image 230
ealeon Avatar asked Oct 14 '13 17:10

ealeon


2 Answers

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.

like image 114
Claudiu Avatar answered Sep 17 '22 22:09

Claudiu


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.

like image 20
Asad Saeeduddin Avatar answered Sep 19 '22 22:09

Asad Saeeduddin