0

Recently i'm reading a book, it mentioned the mro in multiple inheritance, and give sample code:

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

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

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

C()

output:

C
A
B
B

I wanna know why this happen?

2 Answers 2

2

This happens because you're mixing direct constructor calls and calls via super. Your class hierarchy should do either one or the other.

More precisely, the MRO for the class C is C, A, B. Thus, when you call super(A, self).__init__() in A's constructor, that calls the constructor for B, since B succeeds A in C's MRO. In other words, it is inside A's constructor that the first B is printed.

As an aside, writing out super(A, self) is superfluous in Python 3. super() is enough; the arguments are deduced from the context.

Further reading:

Sign up to request clarification or add additional context in comments.

Comments

0

I've converted your code to Python3 (by changing print to print()) and added some more tracing statements:

class A(object):
    def __init__(self):
        print("A", type(self).__mro__)
        super(A, self).__init__()
        print("/A")

class B(object):
    def __init__(self):
        print("B", type(self).__mro__)
        super(B, self).__init__()
        print("/B")

class C(A,B):
    def __init__(self):
        print("C")
        A.__init__(self)
        print("ca/b")
        B.__init__(self)
        print("/C")

C()

Here's the output:

C
A (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
B (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
/B
/A
ca/b
B (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
/B
/C

Looking at the output, you can see the call to the C.__init__ method is happening, and printing 'C'. It then calls A.__init__ directly (which is a mistake- use super!).

The A.__init__ call prints its message, including the __mro__ attribute. You can see the sequence: C -> A -> B -> Object. This is important, because it means that calls to super() from within A.__init__ are going to refer to class B. Also, calls to super from inside C.__init__ would have invoked A.__init__ automatically, if you let them.

The next method, B.__init__, is invoked by the super reference inside A.__init__, as mentioned. It calls Object.__init__, presumably, which prints nothing. ;-)

Both B.__init__ and A.__init__ return, we see the midpoint message ca/b, and then your direct call to B.__init__ is made. It prints a message, but again a reference to super form B.__init__ does nothing, because B is at the tail end of the MRO.

The super() mechanism can deal with all this MRO stuff for you. You shouldn't have to invoke A.__init__(self). Instead, you can just let super handle it, inside C.__init__, but doing this:

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

1 Comment

That's so great! Thank you

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.