From: Steven D'Aprano on
On Thu, 29 Jul 2010 19:29:24 +0200, Jean-Michel Pichavant wrote:

> Steven D'Aprano wrote:
>> [snip]
>>
>> super() is just as explicit as len(), or str.upper(). It says,
>> explicitly, that it will call the method belonging to one or more
>> superclass of the given class.
>>
> Come on Steven, you're better than this :) . Everybody can accurately
> guess what len and upper are doing without looking at the documentation.
> No one can guess for super without closely looking at the documention,
> or even at some good articles on the net which try to clear things up
> about super. And note there is no such article about len or upper.

super() is complex because the problem it is solving is a hard problem.
That doesn't make it implicit, any more than (say) itertools.groupby() is
implicit just because it's complex, or urllib2.request() is implicit just
because some people don't know much about web protocols and have to read
articles about it to learn.


> As someone already said in this list, the main problem with super is
> that it tends to refer to the superclass method while in fact it calls
> the next MRO method.

Why do you think that is a problem? That's what it is supposed to do,
because that's what is needed to correctly implement multiple inheritance.


> "mro" would have been the proper name for "super".

That's your opinion. In any case, whether super() was called super() or
mro() or aardvark() makes no difference to the functionality or whether
it is useful.



--
Steven
From: Steven D'Aprano on
On Fri, 30 Jul 2010 14:43:07 +0200, Jean-Michel Pichavant wrote:

> Quoting Michele's article (I think he's still hanging around this list)
>
> "Readers familiar will single inheritance languages, such as Java or
> Smalltalk, will have a clear concept of superclass in mind. This
> concept, however, has /no useful meaning/ in Python or in other multiple
> inheritance languages".

I have read Michelle Simionato's articles on super in Python. He has
taught me a lot. But on that specific matter, I think he is wrong.

Of course, he is right to say that the concept of *the* superclass is
meaningless in a MI language like Python. If MyClass inherits method
spam() from class A, and inherits method ham() from class B, which is
"the" superclass of MyClass?

But Michelle is wrong to conclude that the problem lies with the concept
of *superclass*. The problem lies with the idea that there is ONE
superclass. By dismissing the entire concept, he is throwing out the baby
with the bathwater.

The useful, and I would argue *correct*, concept of superclass is very
simple. It is a reflection of subclass: if Z is a subclass of A, then A
is a superclass of Z. This follows e.g. superset and subset. We don't
have any problem understanding that a class can have many subclasses. Why
the resistance to the idea that a class can have many superclasses?

Even in a single inheritance language, if we had a class hierarchy

A -> B -> C -> ... -> Y -> Z

it makes perfect sense to describe *all* of A-Y as superclasses of Z,
just as we describe all of B-Z as subclasses of A.



--
Steven
From: Steven D'Aprano on
On Fri, 30 Jul 2010 21:40:21 -0600, Ian Kelly wrote:

> I have to chime in and agree that the name "super" is problematic. I'm
> reading this thread with a sense of alarm because I apparently never
> read the super() documentation too closely (why would I? "Oh, it just
> accesses an attribute from a superclass. Moving on.") and have been
> writing code for the past four years under the impression that super()
> will always refer to a superclass of the current class.

In Python 2.x, super() doesn't know what the current class is. You have
to explicitly tell it. If you tell it a lie, surprising things will
happen.

Assuming you accurately tell it the current class, can you give an
example where super() doesn't refer to a superclass of the current class?



[...]
> On a tangent, is it just me, or is the super() documentation incorrect,
> or at least unclear? Quoting from the first two paragraphs:

Yes, it's a bit unclear, because it's a complex function for dealing with
a complicated situation. But if you have single inheritance, it's simple.
Anywhere you would write

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

you can write

class C(B):
def method(self, *args):
super(C, self).method(*args)


and it will Just Work.



> super(type[, object-or-type])
>
> Return a proxy object that delegates method calls to a parent or
> sibling class of type.

I think that the bit about sibling class refers to super(type, type2)
calls, rather than the super(type, instance) calls which I've been
discussing. I've never needed, and don't understand, the two type version
of super(), so I can't comment on it.


--
Steven
From: Steven D'Aprano on
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