Why exactly is
A.__init__()
B.__init__()
D.__init__()
printed by the following code? In particular:
Why is C.__init__()
not printed?
Why is C.__init__()
printed if I put super().__init__()
instead of A.__init__(self)
?
#!/usr/bin/env python3
class A(object):
def __init__(self):
super(A, self).__init__()
print("A.__init__()")
class B(A):
def __init__(self):
A.__init__(self)
print("B.__init__()")
class C(A):
def __init__(self):
A.__init__(self)
print("C.__init__()")
class D(B, C):
def __init__(self):
super(D, self).__init__()
print("D.__init__()")
D()
B.__init__
is what was supposed to call C.__init__
via super(B, self).__init__()
, and you bypassed that call.Why is C.__init__() not printed?
Because you didn't tell it to. Multiple inheritance involves cooperation and you've used explicit class references, denying that cooperation.
Had you replaced all of the "super-like" calls with super().__init__()
(since you've tagged it Python 3) you'd see output like:
A.__init__()
C.__init__()
B.__init__()
D.__init__()
In fact, you'd see this output if you changed just B
's "super-like" call to either:
super(B, self).__init__()
super().__init__()
So why did A not call C in your case?
It would be redundant to copy the well-outlined answers elsewhere on the site about the MRO.
Why is C.__init__() printed if I put super().__init__() instead of A.__init__(self)?
Because the no-argument super() goes left to right, so B
is looked at first, and then inside B you're using an explicit class reference (A.__init__(self)
). And in doing so you lose all (most*) context that D also had as a superclass C
.
super()
is what helps you navigate the MRO, and would have gotten you to C.__init__()
had you let it. But in B
you're just calling a classmethod of A
.
*As you've noted C.__init__()
is never called. However, C
still shows up in D.__bases__
:
(<class '__main__.B'>, <class '__main__.C'>)
in D.__mro__
:
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
and isinstance(D(), C) is True
.
In short, Python knows that C
is a superclass of D
, but you gave the C.__init__
and end-run with your B.__init__
implementation.