TL;DR: I want a locals() that looks in a containing scope.
Hi, all.
I'm teaching a course on Python programming to some chemist friends, and I want to be sure I really understand scope.
Consider:
def a():
    x = 1
    def b():
        print(locals())
        print(globals())
    b()
Locals prints an empty environment, and globals prints the usual globals. How do I get access to the environment where x is stored? Clearly the interpreter knows about it because I can refer to it.
Related: When does scoping happen? The following nameErrors on a = x+2 only if x=3 is included:
def a():
    x = 1
    def b():
        a = x+2
        x = 3
    b()
If you comment out x=3, the code works. Does this mean that python makes a lexical-scope pass over the code before it interprets it?
Python locals() Function The locals() function returns the local symbol table as a dictionary. A symbol table contains necessary information about the current program.
globals() always returns the dictionary of the module namespace. locals() always returns a dictionary of the current namespace. vars() returns either a dictionary of the current namespace (if called with no argument) or the dictionary of the argument.
The LEGB rule is a kind of name lookup procedure, which determines the order in which Python looks up names. • For example, if we access a name, then Python will look that name up sequentially in the local, enclosing, global, and built-in scope. Local (or function) scope.
What is happening in your code is that when python see's the x=3 line in your b() method, it is recreating x with a scope within the b function instead of using the x with it's scope in the a function.
because your code then goes:
    a = x+2
    x = 3
it is saying that you need to define the inner scoped x before referencing it.
however, when you do not have the assigning of x within the b function python does not attempt to make a lower scoped x and will not throw any errors.
The following code will illustrate this:
def a():
    x = 1
    def b():
        x = 3
        print (x)
    def c():
        print (x)
    b()
    c()
    print (x)
a()
However if you were to declare x as global you could use it within a function, like so:
def a():
    global x
    x = 1
    def d():
        global x
        x += 2
    print (x)
    d()
    print (x)
a()
Python 3 has also added a nonlocal keyword that will let you access a variable from an enclosing scope, usage is like:
def a():
    x = 1
    def d():
        nonlocal x
        x += 2
    print (x)
    d()
    print (x)
a()
Will print the same results as the global example.
In case I miss-read the question:
As per the answer to Get locals from calling namespace in Python:
you can use:
import inspect
def a():
    x = 1
    def d():
        frame = inspect.currentframe()
        try:
            print (frame.f_back.f_locals)
        finally:
            del frame
    d()
a()
to get the local scope of the functions caller.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With