[Python-Dev] LOAD_NAME & classes

Guido van Rossum guido@python.org
Mon, 22 Apr 2002 18:00:15 -0400

> > The "only runtime" rules doesn't require dynamic scopes (I agree
> > that dynamic scopes would be bad).  Dynamic scopes, and your
> > example, mix up the call context with the definition context.  My
> > example takes the definition context, and applies the "is x
> > defined in this scope?" test at runtime instead of at compile
> > time.  Very different!
> Rewrite it trivially:
>     def f():
>        print x
>        x = 12
>     x = 10  # moved the line down
>     f()
> I don't know what you mean by "definition context" (and neither will
> a newbie), but any guess I'm likely to come up with wouldn't include
> the idea that "x = 10" is now in f's definition context.  You would
> have to spell out that there are three namespaces at work here, and
> that what "x" means in f depends on the dynamic state of two of
> them, and simply can't be known in general without running the
> program.  If that's not dynamic scoping, it's too close for me to
> believe a distinction is worth making.

I seem to have trouble explaining what I meant.

Long ago, before I introduced LOAD_FAST and friends, Python had
something that for want of a better term I'll call "lexical scoping
with dynamic lookup".  It did a dynamic lookup in a (max 3 deep: local
/ global / builtin) stack of namespaces, but the set of namespaces was
determined by the compiler.  This does not have the problems of
dynamic scoping (the caller's stack frame can't cause trouble).  But
it also doesn't have the problem of the current strict static scoping.

I like the older model better than the current model (apart from
nested scopes) and I believe that the "only runtime" rule explains why
the old model is more attractive: it doesn't require you to think of
the compiler scanning all the code of your function looking for
definitions of names.  You can think of the interpreter pretty much
executing code as it sees it.  You have to have a model for name
lookup that requires a chaining of namespaces based on where a
function is defined, but that's all still purely runtime (it involves
executing the def statement).

This requires some sophistication for a newbie to understand, but it's
been explained successfully for years, and the explanation would be
easier without UnboundLocalError.

Note that it explains your example above completely: the namespace
where f is defined contains a definition of x when f is called, and
thus the search stops there.

> BTW, I consider Python's treatment of global vs builtin namespaces
> dynamic scoping too, and it's nothing but trouble that globals can
> mask and unmask builtins dynamically.  I'd rather make globals and
> builtins act more like locals now than make locals act more like
> they're dynamically scoped.

Um, that's not what I'd call dynamic scoping.  It's dynamic lookup.
It's trouble for a compiler that wants to optimize builtins, but the
semantic model is nice and simple and easy to explain with the "only
runtime" rule.

> BTW2, I see plenty of UnboundLocalErrors in my own code, and some of
> those have occurred when the same name is also in use as a global.
> It's always been a logic error due to forgetting to initialize a
> local, and usually due to "moving code up" in an editor.  It sure
> wouldn't be doing me any favor to let such code silently pick up
> whatever crap happened to be bound to the same-named global;
> UnboundLocalError is a fine bug-catcher.

You definitely have a point there -- like with most irritating errors,
the coin has two sides.  I don't know which side would waste more
time.  (When UnboundLocalError was still spelled as NameError, I'd bet
on the latter.)
