[Python-3000] [Python-Dev] PEP 367: New Super (original) (raw)

Guido van Rossum guido at python.org
Sat May 26 01:13:17 CEST 2007


On 5/25/07, Tim Delaney <timothy.c.delaney at gmail.com> wrote:

Bah - this should have gone to Pyton-3000 too, since it's discussing the PEP.

My fault; I started sending you feedback that only went to you, Calvin and the PEP editors. I've added python-3000 at python.org back here.

Guido van Rossum wrote:

> - This seems to be written from the POV of introducing it in 2.6. > Perhaps the PEP could be slightly simpler if it could focus just on > Py3k? Then it's up to the 2.6 release managers to decide if and how to > backport it. That was my original intention, but it was assigned a non-Py3k PEP number, so I presumed I'd missed an email where you'd decided it should be for 2.6. We should probably change the PEP number if it's to be targetted at Py3K only.

Maybe. There are a bunch of PEPs that were originally proposed before the Py3k work started but that are now slated for inclusion in 3.0. I don't think we should renumber all of those.

> - Why not make super a keyword, instead of just prohibiting assignment > to it? (I'm planning to do the same with None BTW in Py3k -- I find > the "it's a name but you can't assign to it" a rather silly business > and hardly "the simplest solution".)

That's currently an open issue - I'm happy to make it a keyword - in which case I think the title should be changed to "super as a keyword" or something like that.

As it was before. :-)

What's the argument against?

> - "Calling a static method or normal function that accesses the name > super will raise a TypeError at runtime." This seems too vague. What > if the function is nested within a method? Taking the specification > literally, a nested function using super will have its own preamble > setting super, which would be useless and wrong.

I'd thought I'd covered that with "This name behaves identically to a normal local, including use by inner functions via a cell, with the following exceptions:", but re-reading it it's a bit clumsy. The intention is that functions that do not have access to a 'super' cell variable will raise a TypeError. Only methods using the keyword 'super' will have a preamble. Th preamble will only be added to functions/methods that cause the 'super' cell to exist i.e. for CPython have 'super' in co.cellvars. Functions that just have 'super' in co.freevars wouldn't have the preamble.

I think it's still too vague. For example:

class C: def f(s): return 1 class D(C): pass def f(s): return 2*super.f() D.f = f print(D().f())

Should that work? I would be okay if it didn't, and if the super keyword is only allowed inside a method that is lexically inside a class. Then the second definition of f() should be a (phase 2) SyntaxError.

Was it ever decided whether the implicitly bound class should be:

I've got a hunch that #1 might be more solid; #3 seems asking for trouble.

There's also the issue of what to do when the method itself is decorated (the compiler can't know what the decorators mean, even for built-in decorators like classmethod).

> - "For static methods and normal functions, will be None, > resulting in a TypeError being raised during the preamble." How do you > know you're in this situation at run time? By the time the function > body is entered the knowledge about whether this was a static or > instance method is lost.

The preamble will not technically be part of the function body - it occurs after unpacking the parameters, but before entering the function body, and has access to the C-level variables of the function/method object. So the exception will be raised before entering the function body. The way I see it, during class construction, a C-level variable on the method object would be bound to the (decorated?) class. This really needs to be done as the last step in class construction if it's to bind to the decorated class - otherwise it can be done as the methods are processed.

We could make the class in question a fourth attribute of the (poorly named) "bound method" object, e.g. im_class_for_super (im_super would be confusing IMO). Since this is used both by instance methods and by the @classmethod decorator, it's just about perfect for this purpose. (I would almost propose to reuse im_self for this purpose, but that's probably asking for subtle backwards incompatibilities and not worth it.)

Then when we're calling a bound method X (bound either to an instance or to a class, depending on whether it's an instance or class method), if the im_class_for_super is set, and if the function (im_func) has a "free variable" named 'super', then we evaluate builtin.super(X.im_class_for_super, X.im_self) and bind it to that variable. If there's no such free variable, we skip this step. This step could be inserted in call_function() in Python/ceval.c in the block starting with "if (PyMethod_check(func) && ...)". It also needs to be inserted into method_call() in Objects/classobject.c, in the toplevel "else" block. (The ceval version is a speed hack, it inlines the essence of method_call().)

Now we need to modify the compiler, as follows (assume super is a keyword):

I think this should work; it mostly uses existing machinery; it is explainable using existing mechanisms.

If a function using super is somehow called without going through the binding of super, it will just get the normal error message when super is used:

NameError: free variable 'super' referenced before assignment in enclosing scope

IMO that's good enough; it's pretty hard to produce such a call.

I was thinking that by binding that variable to PyNone for static methods it would allow someone to do the following:

def modulefunc(self): pass class A(object): def func(self): pass @staticmethod def staticfunc(): pass class B(object): func = A.func staticfunc = A.staticfunc outerfunc = modulefunc class C(object): outerfunc = B.outerfunc but that's already going to cause problems when you call the methods - they will be being called with instances of the wrong type (raising a TypeError).

I don't see any references to super in that example -- what's the relevance?

So now I think both static methods and functions should just have that variable left as NULL. Trying to get super(NULL) will throw a TypeError.

See my proposal above. It differs slightly in that the super call is made only when the class is not NULL. On the expectation that a typical function that references super uses it exactly once per call (that would be by far the most common case I expect) this is just fine. In my proposal the 'super' variable contains whatever super(, ) returned, rather than which you seem to be proposing here.

> - The reference implementation (by virtue of its bytecode hacking) > only applies to CPython. (I'll have to study it in more detail later.)

Yep, and it has quite a few limitations. I'd really like to split it out from the PEP itself, but I'm not sure where I should host it.

Submit it as a patch to SourceForge and link to it from the PEP (I did this for PEP 3119). If you still care about it -- I'm also okay with just having it in the subversion archives.

> I'll probably come up with more detailed feedback later. Keep up the > good work!!

Now I've got to find the time to try implementing it. Neal has said he's willing to help, but I want to give it a go myself.

Great (either way) !

PS if you like my proposal, feel free to edit it into shape for the PEP.

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



More information about the Python-3000 mailing list