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