Reputation: 8958
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
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