Easy questions from a python beginner

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Mon Jul 12 19:34:18 EDT 2010


On Mon, 12 Jul 2010 20:28:49 +0200, Alf P. Steinbach /Usenet wrote:

> As I see it it doesn't matter whether the implementation is CPython call
> frame slots or that mechanism called something else or a different
> mechanism called the same or a different mechanism called something
> different; what IMO matters is same semantics, that any assignment to a
> variable within a routine serves as a compile time declaration, creating
> that local variable in advance, unless, with Python 3.x., that name has
> been declared as a 'global' or 'nonlocal'.
> 
> So, this is a possible point of disagreement.
> 
> I say the semantics of local variable creation are part of the language
> definition, but I get the /impression/ that maybe you think it's
> CPython-specific, that e.g.
> 
>    def foo():
>        x
>        x = 0
> 
> might not raise an unassigned variable exception with some conforming
> Python implementation, i.e. different effect for same code with
> different implementations, that this is at least /unspecified behavior/
> in Python?

Almost. 

I believe that "any assignment to a variable within a routine serves as a 
compile time declaration" is a promise of the language, but what an 
implementation does in response to that declaration is unspecified. So 
long as foo() raises NameError, or a subclass of it, it will be a 
conforming Python implementation.

That's what Python 1.5 does, and I think if some competing implementation 
targeted 1.5 we'd still be happy to call it Python. (Although we might 
wonder about the author's sanity...) Implementations are free to subclass 
NameError, as CPython does with UnboundLocalError, but mustn't raise a 
completely unrelated error, or no error at all. E.g. I don't think it 
would be acceptable to implicitly create new names and bind them to some 
arbitrary default value.

E.g. an implementation might do something like this:

* when parsing the function, prior to compiling the byte-code, tag
  every name with a sigil representing whether it is local or non-local;
* compile a single byte-code for name lookup;
* when executing that instruction, if the name is tagged as a local,
  search only the local namespace, otherwise search the nonlocal, 
  global and builtin namespaces;
* when displaying names to the user (say, in tracebacks) suppress 
  the sigil.

Under this implementation, no variable actually exists until it is 
assigned to.

This is equivalent to shifting the decision to use LOAD_FAST or 
LOAD_GLOBAL to runtime rather than compile time, so it would probably 
hurt performance rather than increase it, but it would still be a 
conforming implementation.

But of course I'm not Guido, and he has the final word on what counts as 
acceptable behaviour.



-- 
Steven



More information about the Python-list mailing list