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()
def __init__(self, n) -> None: means that __init__ should always return NoneType and it can be quite helpful if you accidentally return something different from None especially if you use mypy or other similar things.
__init__ is the constructor for a class. The self parameter refers to the instance of the object (like this in C++). class Point: def __init__(self, x, y): self._x = x self._y = y. The __init__ method gets called after memory for the object is allocated: x = Point(1,2)
__init__ in Python: An Overview. Today, a programmer is bound to come across object-oriented programming (OOP) during their career. As a modern programming language, Python provides all the means to implement the object-oriented philosophy. The __init__ method is at the core of OOP and is required to create objects.
"__init__" is a reseved method in python classes. It is known as a constructor in object oriented concepts. This method called when an object is created from the class and it allow the class to initialize the attributes of a class.
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.
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