Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is an __init__ skipped when doing Base.__init__(self) in multiple inheritance instead of super().__init__()?

Why exactly is

A.__init__()
B.__init__()
D.__init__()

printed by the following code? In particular:

  1. Why is C.__init__() not printed?

  2. 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()
like image 280
user541686 Avatar asked Oct 07 '18 06:10

user541686


People also ask

What is __ init __( self -> None?

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.

What is the need of def __ init __( self Param?

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

Is __ init __ necessary in Python?

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

What does __ init __( self do in Python?

"__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.


1 Answers

tl;dr: because 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.

  • How does Python's super() work with multiple inheritance?
  • How does Python's "super" do the right thing?

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.

like image 91
jedwards Avatar answered Oct 07 '22 01:10

jedwards