[Python-Dev] peps 329, 266, 267

Phillip J. Eby pje at telecommunity.com
Wed Apr 21 13:48:33 EDT 2004

At 12:28 PM 4/21/04 -0400, Jewett, Jim J wrote:

>How about
>         from __future__ import noshadow
>         <==>
>         If a name (or its immediately enclosing class)
>         is explicitly declared dynamic, semantics are
>         the same as today.

How do you declare that something is dynamic?

>         For all other names, the compiler may assume that
>         the nearest enclosing binding of this name will
>         always be in the same namespace.  (Names need not
>         all be in a single namespace, but once a particular
>         name is found, that namespace will always be the
>         correct place to look for that name.)
>         Results are undefined if the name is later unbound
>         in that namespace or shadowed by a nearer enclosing
>         namespace.

This actually isn't that different from my proposal for builtins, except 
that my proposal doesn't have "undefined results".  Instead, names that are 
determined to be builtin are not allowed to be bound via __setattr__, and 
are never looked up in the globals dictionary.

>Question:  Should the compiler be able to assume the
>same *object* (=can bind as local), or only the same
>namespace (=can do with a single indirection, perhaps
>sped up with a variant of DLict).
>Question:  Is there any reason that this should apply
>only to builtins, rather than to any namespace?

Simplicity.  Functions today do only three kinds of lookups: LOAD_CELL(?), 
LOAD_FAST and LOAD_GLOBAL.  LOAD_CELL is an indirect load from a known, 
specific nested scope.  LOAD_FAST loads from an array offset into the 
current frame object.  LOAD_GLOBAL checks globals and then 
builtins.  Module-level and class body code use LOAD_NAME, which looks in 
locals, globals, and builtins.

Module and class body code is almost never important for application 
performance, certainly not enough to justify effort on optimization, I think.

So that leaves LOAD_GLOBAL, which I suggest leaving alone in favor of 
adding LOAD_BUILTIN and/or CALL_BUILTIN.  In other words, at that point all 
lookups made by functions *would* be explicit as to scope, since 
LOAD_GLOBAL could only fail its first lookup if the global in question was 
a not-yet-shadowed-but-expected-to-be builtin.

>Objection:  Users can do something undefined and get
>"normal" results instead of a warning -- on their own
>platform.  They can even do this strictly through
>changes to other modules which do not themselves
>import noshadow.  How serious is this objection?

I think my proposal adequate deals with this by disallowing shadowing at 
runtime.  And, if it was desired to disallow shadowing by modifiying 
globals(), then perhaps globals() and module.__dict__ could simply return a 
dictionary proxy that prevented modification of the disallowed 
values.  (But the bare dictionary would still be used by the eval loop.)

>If a warning is required, will the bookkeeping be
>needed even in release mode, or will it be an option
>depending on compiler settings?

The runtime checking in my proposal only requires a bit of work at module 
setup, and checking when a module attribute is set.  Neither of these occur 
frequently enough in general to be concerned about.

More information about the Python-Dev mailing list