Alex
Alex

Reputation: 19803

super in python 3, when class only has inherited function

Newbie question on super(): In the toy example below, I was surprised that the output is C and not A since J in inherits foo from A. Here is the code:

class A:
    def foo(self):
        return 'A'


class C(A):
    def foo(self):
        return 'C'


class J(A):
    pass


class E(J, C):

    def f(self):
        return super().foo()

    def foo(self):
        return 'E'

print(E().f())

J inherits foo from A; the MRO of E is:

(<class '__main__.E'>, <class '__main__.J'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

so how come 'A' isn't the return value? ie evaluation proceeds to C

Upvotes: 0

Views: 39

Answers (1)

Olivier Melan&#231;on
Olivier Melan&#231;on

Reputation: 22314

The class super does not just recover the superclass. It instantiate an object which recovers methods in the context of a given method resolution order. This answer features a reimplementation of super in Python to help you understand how it resolves a method inheritance.

So, as you can see, the method resolution order of your class is (E, J, C, A, object). Since it comes up first, then E inherits foo from C and not A.

Now the question you are probably asking is...

Why does C comes before A?

The C3 linearization algorithm which builds the mro has the property that if some class X inherits from Y, then it will come prior to Y in the mro.

As you can see, this is respected in your example. The class C inherits from A and thus has to come first.

The following example demonstrates that as soon as you were to drop the A inheritance from C, then the result becomes the one you were mistakingly expecting.

class A:
    pass

class C: # Dropped A inheritance
    pass

class J(A):
    pass

class E(J, C):
    pass

E.__mro__ # (E, J, A, C, object)

Upvotes: 3

Related Questions