Builtn super() function. How to use it with multiple inheritance? And why should I use it at all?

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Sun Aug 1 09:38:44 CEST 2010


On Sat, 31 Jul 2010 13:29:25 +0000, Brian Victor wrote:

> Steven D'Aprano wrote:
>> On Sat, 31 Jul 2010 14:25:39 +1200, Gregory Ewing wrote:
>>
>>> Steven D'Aprano wrote:
>>> 
>>>>       A
>>>>      / \
>>>>     C   B
>>>>      \ /
>>>>       D
>>>>      / \
>>>>     E   F
>>>> 
>>>> Yes, a super call might jog left from C to B, but only when being
>>>> called from one of the lower classes D-F. That's still an upwards
>>>> call relative to the originator, not sidewards.
>>> 
>>> But it's not an upward call relative to the class mentioned in the
>>> super() call, which is why I say it's misleading.
>>
>> Which class would that be?
>>
>> I think I'm going to need an example that demonstrates what you mean,
>> because I can't make heads or tails of it. Are you suggesting that a
>> call to super(C, self).method() from within C might call
>> B.method(self)?
> 
> Yes, it would.
[snip example]

Right, now I see what you mean. I don't have a problem with that 
behaviour, it is the correct behaviour, and you are making the call from 
D in the first place, so it *must* call B at some point.

If you initiate the call from C instead:

>>> C().test_mro()
In C
In A

then B is not in C's MRO, and does not get called. This is the case I was 
referring to.

I admit it did surprise me the first time I saw the example you gave. 
Hell, it *confused* me at first, until I realised that self inside the 
method isn't necessarily an instance of C, but could be an instance of a 
subclass of C (in this case, D), and then it was "Well duh, how obvious!" 
That's no different from a classic-style call to a superclass:

# inside class C(B):
B.method(self, *args)

Inside B, method() gets called with an instance of C as self.

Bringing it back to super(), since super(C, self) gets a D instance as 
argument, the MRO it looks at is D's MRO, and it all just works. I think 
the docs could make that a little more clear, but then, given how non-
cooperative inheritance works exactly the same way, there's a good 
argument for saying the docs don't need to be changed at all. If the 
behaviour is confusing for super(), then it's confusing without super() 
too.

See Guido's tutorial on cooperative multitasking for more detail:

http://www.python.org/download/releases/2.2.3/descrintro/#cooperation


> Since the idea of super() as I understand it is to make sure every class
> in an object's hierarchy gets its method called, there's really no way
> to implement super() in a way that didn't involve a non-superclass being
> called by some class's super() call.

You're reading the super() signature wrong.

super(C, self)

shouldn't be interpreted as "call C's superclasses from self". It means 
"starting just after C in the MRO, call self.__class__'s superclasses".

super() never calls a non-superclass. If it did, it would be a huge bug, 
and inheritance would break.




-- 
Steven



More information about the Python-list mailing list