understanding MRO, constructors, and methods in multiple inheritance of python

Question:

following is the two set of codes: one having constructor __init__(), and another having display() method.

code one:

class A(object):
    def __init__(self):
        self.a = "a"
        print(self.a)
        super().__init__()

class B(object):
    def __init__(self):
        self.b = "b"
        print(self.b)
        super().__init__()

class C(A,B):
    def __init__(self):
        self.c = "c"
        print(self.c)
        super().__init__()

o = C()
print(C.mro())

if we compile and run this above set of codes, output will be:

c
a
b
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

now, Second block of code is below,

class A(object):
    def display(self):
        self.a = "a"
        print(self.a)
        super().display()

class B(object):
    def display(self):
        self.b = "b"
        print(self.b)
        super().display()

class C(A,B):
    def display(self):
        self.c = "c"
        print(self.c)
        super().display()

o = C()
o.display()
print(C.mro())

if in above second block of code we replace __init__() with display() method then,
BECAUSE OF super().display() in class B, error will be shown
also if we remove super().display() in class B their will be no error

AttributeError: 'super' object has no attribute 'display'

which I understand, because OBJECT class does not have display() method in it.
but in the first block of code, the code runs without error.

Does that means OBJECT CLASS of python have __init__() in it?

if not, please explain me why their is no error in first block of code but their is error in second block of code?

Asked By: Sandeep Chetia

||

Answers:

Let’s break this code down:


First snippet:

class A(object):
    def __init__(self):
        self.a = "a"
        print(self.a)
        super().__init__()


class B(object):
    def __init__(self):
        self.b = "b"
        print(self.b)
        super().__init__()

This is a regular class in Python, no need to elaborate – it inherits from object – (which in Python3 is redundant) it calls a the super().__init__() which translates to object().__init__() – every class in Python inherits from object – we can see it by calling the method resolution order and noticing <class 'object'> in the list (last element/ only element). Same story for class B.

class C(A,B):
    def __init__(self):
        self.c = "c"
        print(self.c)
        super().__init__()

Here we have complicated things up – we have inherited from two classes: A and B. Also calling super().__init__() – which calls A.__init__() and B.__init__() – thus printing in the order you’ve seen: c, a, b.


Second snippet:

This where things break.

class A(object):
    def display(self):
        self.a = "a"
        print(self.a)
        super().display()

This is again, a regular class in Python with the redundant inheritance from the object class – but now we are calling super().display() – which translates to object().display() – and that method does not exist:


>>> object().__init__()

None


>> object.display()

AttributeError: type object 'object' has no attribute 'display'

TL;DR:

Yes, the object class does have __init__(), here it is:

def __init__(self): # known special case of object.__init__
    """ Initialize self.  See help(type(self)) for accurate signature. """
    pass

no, it does not have .display().

Answered By: no_hex