Question

I've been trying to understand the behavior of super() in the context of multiple inheritance. I'm confused as to why the calls to super() in the parent classes in test2.py cause __init__() to be called for both parents?

test1.py

#!/usr/bin/env python

class A(object):

    def __init__(self):
        self.A = "A"
        print self.A

class B(object):

    def __init__(self):
        self.B = "B"
        print self.B

class C(A, B):

    def __init__(self):
        self.C = "C"
        print self.C
        super(C, self).__init__()

if __name__ == '__main__':
    print "Without super() in parent __init__():"
    c = C()
    print c.__dict__
    print C.__mro__

produces:

$ ./test.py 
Without super() in parent __init__():
C
A
{'A': 'A', 'C': 'C'}
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>)

test2.py

#!/usr/bin/env python

class A(object):

    def __init__(self):
        self.A = "A"
        print self.A
        super(A, self).__init__()

class B(object):

    def __init__(self):
        self.B = "B"
        print self.B
        super(B, self).__init__()

class C(A, B):

    def __init__(self):
        self.C = "C"
        print self.C
        super(C, self).__init__()

if __name__ == '__main__':
    print "With super() in parent __init__():"
    c = C()
    print c.__dict__
    print C.__mro__

produces:

$ ./test2.py 
With super() in parent __init__():
C
A
B
{'A': 'A', 'C': 'C', 'B': 'B'}
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>)
Was it helpful?

Solution

Your mistake is in your comment:

super(C, self).__init__()  <-- call to object.__init__()

This is not a call to object.__init__. The reason that you pass both the class C and the instance self to super is so that it knows what to call next, not just based on the superclasses of the class, but based on the MRO of the instance. Essentially, super(C, self).__init__ means "call the __init__ of the class after C in self's MRO".

This is the whole point of super --- it allows cooperative inheritance where a class can just call super to mean "pass control the next class in the MRO", without needing to know at class definition time which class that is.

So when you call super(C, self).__init__, that calls A.__init__, because A is the next class after C in the MRO. Then when A calls super(A, self).__init__, that calls B.__init__, because B is the class after A in the MRO.

(Note that your messages are printed in reverse order --- B, A, C --- because you print each message after calling the superclass method. So the first message doesn't get printed until executing gets all the way up to B.__init__, and then the other messages are printed on the way back down the inheritance tree.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top