Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python locals() for containing scope

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?

like image 958
mmtrebuchet Avatar asked Feb 25 '13 22:02

mmtrebuchet


People also ask

What does locals () do in Python?

Python locals() Function The locals() function returns the local symbol table as a dictionary. A symbol table contains necessary information about the current program.

What's the difference between globals () locals () and VARS ()?

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.

What is LEGB rule in Python?

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.


1 Answers

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.

like image 86
Serdalis Avatar answered Sep 22 '22 01:09

Serdalis