[Python-3000] Fixing super anyone?

Guido van Rossum guido at python.org
Fri Apr 20 19:53:23 CEST 2007


On 4/20/07, Thomas Wouters <thomas at python.org> wrote:
> On 4/19/07, Jim Jewett <jimjjewett at gmail.com> wrote:
> > On 4/18/07, Guido van Rossum <guido at python.org> wrote:
> > > Is anyone available to write up a PEP on how to turn super into a
> > > keyword? Inside regular and class methods, super.foo(args) should be
> > > equivalent to super(ThisClass, self).foo(args). I think there are ways
> > > to make the old syntax work too, but maybe that's only necessary for
> > > 2.6.
> >
> > Does this mean it should find the super of the current class (which
> > isn't yet defined when the method is being defined)?
> >
> > That would be a slight change (though probably an improvement) against
> > today's lookup-by-name.
> >
> > If that change is OK, and no one else volunteers, I'll try to take a
> > go at it this weekend.
>
> I've had this near the top of my (Python) TODO list for a while, but I
> haven't been able to find the time. I've considered it while doing the
> dishes and such, though.

(Not in the shower? :-)

> I can think of two ways of doing the underlying
> magic "properly", and one way that's too ugly to think about:
>
>  1) Add a new type of descriptor-hook, for associating an object with the
> class it is an attribute of. After class creation (in the metaclass
> __init__), any object with this __associate__ (or whatever) hook gets it
> called. It's only called for objects that are attributes of *that* class,
> not of any superclasses (since they will already be associated with the
> superclass.) I'm sure there are other uses for this hook, just not methods
> that want to use super() -- like zope interfaces ;)

Nice and elegant. Though what would the hook *do*? I.e. where does it
store the class reference for super to find? Perhaps this is where my
idea of a designated cell comes in handy (although you'd end up with a
cell per method instead of all methods sharing one cell).

Also, what arguments are passed to the hook? For this purpose the
class object is the only thing needed -- but is that always
sufficient?

>  2) Add a new argument to __get__ (or a new method that acts like __get__
> but with the extra argument, and is called instead of __get__ if it is
> defined) where the extra argument is the class that the retrieved descriptor
> is actually an attribute of. It currently (correctly) gets the class the
> attribute was retrieved through, which could be a subclass.

I'm not so keen on this; calling an existing API with an extra
argument is fraught with transitional problems (2to3 notwithstanding).
And checking for two different special methods slows things down. I'd
propose to pass the class where it's found as the 3rd arg always,
since (almost) nobody uses this argument, but I'm not sure of the
consequences for class methods.

Anyway, this also still requires us to answer how that extra argument
gets passed on to the executing code -- but now a cell won't do, as
the argument may be different (theoretically anyway) on each call to
__get__. So that also makes me wary because this adds overhead per
call (technically: per lookup that binds a method) while the thing we
need to pass on typically only changes if the class changes -- so
doing some magic at class creation time makes more sense to me.

(Of course, there's the issue what to do if we dynamically define a
new function, and poke it into a class as a method, and that function
needs to use super. IMO it's fine to require such a function to use
the underlying super() machinery -- this must be an exceedignly rare
case!)

> In both these cases, the (un)bound method object would end up with knowledge
> of the class it is defined in, and create a local variable with a
> super-object for the 'super' keyword to use.

Ah, so you propose to store it in a local variable. But where is it
stored before the function is called? I guess on the "bound method"
object. But how is the value passed on as part of the call? I like a
cell a lot better because we have an established way to pass cells
into calls.

> There still are some grey areas
> to solve -- what if classes share functions, what if functions share
> code-objects, etc. #2 is probably a better way to go about it than #1, in
> that regard.

Sharing functions is very rare and IMO it's okay if the mechanism
doesn't work in that case -- as long as it fails loudly. Sharing code
objects shouldn't be a problem -- code objects are immutable anyway,
cells are associated with the function object, not with the code
object.

> (and 3) the fugly method: don't do anything special with methods, but have
> super() search through __mro__ for the first class to have the current
> function as an attribute, then pick the next class from that. Yecch, and
> more grey areas than the other two methods.)

This does not get my vote.

> There's also the question of what the super keyword itself should look like,
> e.g.
>
>   # declaration-style, no dot
>   res = super currentmethod(arg, arg)
>   # treat super like self
>   res = super.currentmethod (arg, arg)
>   # treat super like self.currentmethod
>   res = super(arg, arg)
>
> I think super.currentmethod(arg, arg) makes the most sense, but that may be
> because it most closely resembles the current practice. However, it may call
> the "wrong" supermethod when the class does, for instance, '__repr__ =
> __str__'.

Depends on how you define "wrong". :-)

I am strongly in favor of super.currentmethod(...) if only because
that's closest to how we've always done it, and there may even be a
use case for callong some *other* super method.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)

My signature virus killed your signature virus!


More information about the Python-3000 mailing list