Despite it's name, super()
is not calling on "the" parent class (which makes no sense since with multiple inheritance you can have more than one single parent class...) but on the next class in the __mro__
.
In you case, the mro for D
is C, B, A
, so D.foo
will call C.foo
which will call B.foo
which will call A.foo
.
If what puzzles you is that super(C, self).foo
resolves to B.foo
even while C
doesn't inherit from B
, you have to remember that super
will use the mro of self
, which in this case DOES include B
since self
here is a D
instance, not a C
instance. That's actually whysuper
needs both the current class and the current instance FWIW.
Is it because class C gets a parent class from class D's inheritance?
Almost... that's not how it works (cf above), but the effective result is quite similar.
I was expecting super(C,self).foo() will throw exception
It will if the class super()
resolves too has no foo
method (or if it has a non-callable foo
attribute):
class E(C):
def foo(self):
print("!E")
super(E,self).foo()
print("E")
E().foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "sup.py", line 65, in foo
super(E,self).foo()
File "sup.py", line 50, in foo
super(C,self).foo()
AttributeError: 'super' object has no attribute 'foo'
And this comes from the super(C, self).foo()
call in C
- in this case, the next class in E.__mro__
is object
, which doesn't indeed define a foo
method ;-)