Nested scopes: why is it weird?
aleax at aleax.it
Fri Sep 7 18:57:19 CEST 2001
"Scott Long" <scott at swiftview.com> wrote in message
news:3B98F3B0.53AC2524 at swiftview.com...
> Nested scopes seem like a nice addition (of course!) but there are some
> weird things about it. Take a look:
Not really, just a typical misunderstanding (which also existed
wrt global variables before nested scopes).
> Right, this is what you would expect. But how about this?
> >>> from __future__ import nested_scopes
> >>> def a():
> ... def b():
> ... k = x
> ... x = 0
The x name in procedure b is LOCAL -- the compiler knows it,
because x is re-bound in b's scope. (Incidentally, you can
never rebind a name from a lexically-nested local scope
in your scope; you CAN rebind a global name, if you use the
global statement at the start of a function).
> My first beef here is, why is the exception called UnboundLocalError?
Because x is a local name, and it is not yet bound when it is
first used in b's first instruction.
> The variable is certainly bound (into the local scope), it simply has
Nope. x is a local name, but not bound to any value, as yet.
Only the assignment statement (if it was executed) would bind
name x (to the value 0).
> not been assigned. Why not call it UninitializedLocalError? I know it
> isn't going to change, I'm just asking.
> But my main concern is that this way of selecting a binding seems very
> unintuitive. Shouldn't the first statement referencing x be the
> statement that specifies the binding of x? In this case, shouldn't "k =
*In general*, how could the compiler tell what the first statement
IS, that _references_ name x within a given scope? Assuming you
mean, "first to execute". The compiler _might_ assign some
arbitrary ordering, of course. But having:
have *TOTALLY* different semantics from:
when it SEEMS they're totally equivalent, would be truly weird, so
I don't think you mean "first in some arbitrary order (such as,
longest-first, or lower-line-number-first, or whatever)".
> x" cause x to get bound as a free variable, not a local to b()? I'm not
> claiming that this is a bug. I am curious as to why it was decided that
> things are going to work this way. It makes assignment to a variable in
> an enclosing scope impossible!
Yes, the latter is exactly Guido's decision: he has always maintained
that the right (aka obvious) way for something to keep and update
state is to define a class, rather than stretch closures to let code
in them re-bind things "partways up" -- or so I hear, and I sure
see his point. But it's not any kind of necessary consequence of
Python's long-standing rules that all variables re-bound in a scope
are local to that scope unless explicitly mentioned in a global
statement -- it would have been trivial to say, for example, that
"global x in a" was THE way for b to inform the compiler that the
x name b uses and re-binds is the one in a, not one local to b itself
(somebody wanting to make closures really powerful/handy might have
stretched that to "global x in a as z":-).
Java just doesn't let a local variable 'shadow' one with the
same name from a lexically-outer scope, and that might have
been a nice choice too -- just forbid b to have a local variable
named x if a lexically-outer scope of b had a similarly named
local variable. Unfortunately, this restriction, which I have
always liked, and proposed when nested scope were PEP'd, was
not accepted (though it did get a mention in the PEP), so we'll
live forevermore with misunderstandings on this point.
More information about the Python-list