[Python-Dev] LOAD_NAME & classes (original) (raw)

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.)

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