Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Question related to super() with __init__()

Tags:

python

super

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.

like image 611
Kelvin Avatar asked May 20 '19 08:05

Kelvin


People also ask

What does super () __ init __ do?

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.

Is super () necessary Python?

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 ).

How does super () work in Python?

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.


2 Answers

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.

like image 56
gmds Avatar answered Oct 20 '22 21:10

gmds


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.

like image 1
gachdavit Avatar answered Oct 20 '22 20:10

gachdavit