Name resolution and the (wrong?) LEGB rule

Steve D'Aprano steve+python at pearwood.info
Thu Dec 8 19:00:47 EST 2016


On Fri, 9 Dec 2016 01:51 am, Marco Buttu wrote:

> Sometimes the Python name resolution is explained using a LEGB rule.
> For instance, in [1] (I think also the Learning Python book gives the
> same):
> 
> "if a particular name:object mapping cannot be found in the local
> namespaces, the namespaces of the enclosed scope are being searched
> next. If the search in the enclosed scope is unsuccessful, too, Python
> moves on to the global namespace, and eventually, it will search the
> built-in namespace (side note: if a name cannot found in any of the
> namespaces, a NameError will is raised)."
> 
> AFAIK, Python has static scoping: the scope for a name is given during
> the bytecode compilation. This means that before executing the program,
> Python already know in which namespace to look for an object. So, it
> seems to me that the LEGB rule is wrong, and this is what actually
> happens:
> 
> * local name (LOAD_FAST instruction): Python looks (only) in the local
> namespace, and if it does not find the name, then it raises an
> UnboundLocalError
> 
> * global name (LOAD_GLOBAL): at first Python looks in the globals(), and
> in case the name is not there, it looks in the builtins namespace; if
> the name is neither in the global nor in the builtin namespace, it
> raises a NameError
> 
> * enclosing scope (LOAD_DEREF): there is a closure, and Python looks for
> the name in the enclosing namespace
> 
> Is that right, or am I missing something? Thanks, Marco

You are partly right, but you are also missing a few things.

(1) Technically, the LOAD_* byte codes are implementation details, and there
is no requirement for Python interpreters to use them. In fact, Jython
being built on the JVM and IronPython being built on the .Net runtime
cannot use them. Even a C-based interpreter is not required to implement
name resolution in the same way. 

(2) There are some odd corner cases in Python 2 where you use exec() or
import * inside a function to create local variables, where the CPython
interpreter no longer uses LOAD_FAST to resolve locals. (I'm going by
memory here, so I may have some of the details wrong.) You can experiment
with that if you like, but the behaviour has changed in Python 3 so its no
longer relevant except as a historical detail for those stuck on Python 2.

(To be precise, import * is forbidden inside functions, and exec() must take
an explicit namespace argument rather than implicitly applying to the local
function scope.)


(3) However, the most important case you've missed is code executed inside a
class namespace during class creation time:


class C(object):

    a = 1

    def test():  # intentionally no self
        b = 2
        return a + b

    c = 3
    d = test() + c



Don't forget classes nested inside classes...


I consider the LEGB rule to be a statement of intent, describing how a
Python implementation is expected to behave, *as if* it were following the
LEGB rule, not necessarily a statement of the implementation of any
specific Python implementation.





-- 
Steve
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.




More information about the Python-list mailing list