steffen
steffen

Reputation: 8958

Access method of second base class with super()

Please explain to me the following. If I execute this:

class Base1:
    def foo(self):
        print('in Base1.foo')

b1 = Base1()
b1.foo()


class Base2:
    def foo(self):
        print('in Base2.foo')

b2 = Base2()
b2.foo()

class Child1(Base1, Base2):
    def foo(self):
        super(Child1,self).foo()

c1 =  Child1()
c1.foo()

class Child2(Base1, Base2):
    def foo(self):
        super(Base1,self).foo()

c2 =  Child2()
c2.foo()

I get this:

in Base1.foo
in Base2.foo
in Base1.foo
in Base2.foo

I understand the first three lines of the output. But why do I have to give the name of the first base class to super() in order to get the method of the second base class?

Upvotes: 1

Views: 72

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1121804

You are mucking with the Method Resolution Order, or MRO. Python class inheritance hierarchies are linearised, given a specific order, according to a system called the C3 linearisation.

super() uses that order to find the next attribute (including methods) in that ordering. Given a current instance, and a class, it'll search the order for an attribute past the given class. For both Child* classes, the MRO lists the Child* class first, followed by Base1 and Base2. In your last example you told super() to go looking in that MRO starting from the next class after Base1, so only Base2.foo() remains to be found.

You can ask any class for its MRO by calling the class.mro() method:

>>> Child2.mro()
[<class '__main__.Child2'>, <class '__main__.Base1'>, <class '__main__.Base2'>, <class 'object'>]

super() can be used outside methods too; you can then easily see what happens when you pick different starting points for the search:

>>> super(Child2, Child2()).foo
<bound method Base1.foo of <__main__.Child2 object at 0x10f40ff98>>
>>> super(Base1, Child2()).foo
<bound method Base2.foo of <__main__.Child2 object at 0x10f40ffd0>>
>>> super(Base2, Child2()).foo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'super' object has no attribute 'foo'

Upvotes: 4

Related Questions