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
(, , , , )
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:
Fourth.__init__ is called.Fourth.__init__ calls Second.__init__ via super.Second.__init__ calls Third.__init__ via super.Third.__init__ prints "third"Second.__init__ prints "second"Fourth.__init__ prints "that's it".In the second example:
Fourth.__init__ is called.Fourth.__init__ calls Second.__init__ via super.Second.__init__ prints "second"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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With