Given 3 classes below,
class A(object):
def __init__(self):
print('A')
def test(self):
print('1')
class B(A):
def __init__(self):
super(B,self) ## if .__init__() is not given here
print('B')
class C(B, A):
def __init__(self):
super(C, self).__init__()
print('C')
If I run D = C()
, it will return
B
C
If I run print(C.__mro__)
,
it will gives (<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
.
I think that means class A will be executed as it is inside the mro
list.However, this is not the case.
I want ask why .__init__()
is necessary for A.__init__()
happening.
Understanding Python super() with __init__() methods It is known as a constructor in Object-Oriented terminology. This method when called, allows the class to initialize the attributes of the class. The super() function allows us to avoid using the base class name explicitly.
In general it is necessary. And it's often necessary for it to be the first call in your init. It first calls the init function of the parent class ( dict ).
The super() function in Python makes class inheritance more manageable and extensible. The function returns a temporary object that allows reference to a parent class by the keyword super. The super() function has two major use cases: To avoid the usage of the super (parent) class explicitly.
That is not what it means!
I think you are actually confused about two things: what mro
is, and the nature of subclass constructors in Python. Let's look at mro
first.
mro
means "method resolution order", and specifies the order in which the Python interpreter will look for appropriately named methods.
So, say you have the following class hierarchy:
class A:
def deepest(self):
print('I wonder where this is coming from...')
def deeer(self):
print('deeper from A')
def deep(self):
print('deep from A')
class B(A):
def deeper(self):
print('deeper from B')
def deep(self):
print('deep from B')
class C(B):
def deep(self):
print('deep from C')
c = C()
c.deep()
c.deeper()
c.deepest()
print(c.__mro__)
Output:
deep from C
deeper from B
I wonder where this is coming from...
(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
When we call deep
, Python looks for it in C
, since C
is first in the mro
. It finds it and goes no further.
On the other hand, for deeper
, Python cannot find it in C
and therefore goes to the next one in the hierarchy, which is B
, and finds it.
Same thing for deepest
, which is only found in A
.
Now, let's connect this to __init__
.
In this case, when you call __init__
from super
, Python looks for the first superclass in the hierarchy, which is B
, and calls its __init__
method.
However, if the __init__
method of B
does not call A.__init__
, then the chain stops there!
Unlike other languages, subclasses do not automatically call the __init__
method of their superclasses, unless of course they have not defined their own __init__
methods, then it is a case of c.deeper()
, as above.
This is in line with Python's philosophy of "we're all consenting adults here" - if you don't want to call the superclass's __init__
, then sure, do it, but you bear the consequences.
class A:
def __init__(self):
print('A.__init__()')
class B(A):
def __init__(self):
print('B.__init__()')
super().__init__() # this will call A.__init__()
b = B()
Because this is python behaviour. If you have A
and B
class and A
is parent of B
and B
also has __init__
method, you should call A.__init__
manually. Otherwise, python will override it. You need explicit call !
We have __init__
in python (Something like constructor). You should call it manually in some cases. It's not called automatically as it's in other languages.
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