In Raymond Hettinger\'s talk \"Super considered super speak\" at PyCon 2015 he explains the advantages of using super
in Python in multiple inheritance context. Thi
Just to clarify, there are four cases, based on changing the second line in Pizza.order_pizza
and the definition of OrganicPizza
:
super()
, (Pizza, OrganicDoughFactory)
(original): 'Making pie with pure untreated wheat dough'
self
, (Pizza, OrganicDoughFactory)
: 'Making pie with pure untreated wheat dough'
super()
, (OrganicDoughFactory, Pizza)
: 'Making pie with insecticide treated wheat dough'
self
, (OrganicDoughFactory, Pizza)
: 'Making pie with pure untreated wheat dough'
Case 3. is the one that's surprised you; if we switch the order of inheritance but still use super
, we apparently end up calling the original DoughFactory.get_dough
.
What super
really does is ask "which is next in the MRO (method resolution order)?" So what does OrganicPizza.mro()
look like?
(Pizza, OrganicDoughFactory)
: [, , , , ]
(OrganicDoughFactory, Pizza)
: [, , , , ]
The crucial question here is: which comes after Pizza
? As we're calling super
from inside Pizza
, that is where Python will go to find get_dough
*. For 1. and 2. it's OrganicDoughFactory
, so we get the pure, untreated dough, but for 3. and 4. it's the original, insecticide-treated DoughFactory
.
Why is self
different, then? self
is always the instance, so Python goes looking for get_dough
from the start of the MRO. In both cases, as shown above, OrganicDoughFactory
is earlier in the list than DoughFactory
, which is why the self
versions always get untreated dough; self.get_dough
always resolves to OrganicDoughFactory.get_dough(self)
.
* I think that this is actually clearer in the two-argument form of super
used in Python 2.x, which would be super(Pizza, self).get_dough()
; the first argument is the class to skip (i.e. Python looks in the rest of the MRO after that class).