scope of globals, locals, use with exec()

Nico Schlömer

I'm having a hard time understanding the scope of globals(), locals() in Python. Consider the following code:

def f1(glob, loc):
    exec("b = 5", glob, loc)


f1(globals(), locals())
print(b + 1)

This passes globals and locals to f1 where the variable b = 5 is defined, and sure enough it's present after the function call in the main scope. The code correctly prints

6

To my surprise, when doing the same in the scope of a function, f2 here, it fails:

def f1(glob, loc):
    exec("b = 5", glob, loc)


def f2():
    f1(globals(), locals())
    print(b + 1)


f2()
Traceback (most recent call last):
  File "/tmp/q.py", line 10, in <module>
    f2()
  File "/tmp/q.py", line 7, in f2
    print(b + 1)
NameError: name 'b' is not defined

Why is that? Is it possible to generalize f1 to allow it to be called from f2 as well?

Mike Scotty

In your first example, locals is the globals dict, because you're on a module level.

You can check that with print(id(globals()), id(locals()))

In your second example, locals is a different dict in the scope of the function.

So to make example 2 work, either use:

def f1(glob, loc):
    exec("b = 5", glob, loc)
def f2():
    f1(globals(), globals())
    print(b + 1)
f2()

or

def f1(glob, loc):
    exec("b = 5", glob, glob)
def f2(loc):
    f1(globals(), loc)
    print(b + 1)
f2(locals())

So this isn't really a matter of exec() but of in which scope you're calling locals().

And ofc it's also a matter of what the code in exec does, because an assignment changes the scope of the name to the current (local) scope, unless global/nonlocal is involved. That's why b=5 is executed in the local scope - except that in your first example, the "local" scope is the global scope.


Follow-up:

if you want to re-assign a value to b in f2 you will need the global keyword:

def f1(glob, loc):
    exec("b = 5", glob, loc)
def f2():
    f1(globals(), globals())
    global b
    b += 1
    print(b + 1) # 7
f2()

Note that this has nothing to do with exec and passing around locals() / globals() - you can reduce it to this example, which would also fail w/o the global keyword (it would throw an UnboundLocalError: local variable 'b' referenced before assignment error).

b = 5
def f2():
    global b
    b += 1
    print(b + 1) # 7
f2()

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Globals and Locals

locals() vs globals() in function

Does F# have a language construct to access the lexical scope (like python locals()/globals())

Python - How to obtain a dictionary(or even a list) of variables in a specific scope; more specific than locals/globals()

Recursion at exec() level with globals

eval globals and locals argument do not work as expected

about pandasql locals() and globals() method issue

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

locals() and globals() in stack trace on exception (Python)

How to execute a callable in a given context (locals and globals)?

difference between locals() and globals() and dir() in python

Python3 globals() and locals() contents

python quits unexpectedly when using locals() or globals()

Destruction order between globals and static function locals

How does exec work with locals?

python use of variable from globals without defining it as global in thee local scope

globals(), locals(), vars() do not work as expected in a function of python

Is it possible to get locals() and globals() from an upper stack frame?

Using a list comprehension to look up variables works with globals() but not locals(). Why?

Is there are any way make locals() and globals() defaultdict-like

C++ - Different concurrent behavious when using locals and globals

use boolean locals in pug

list comprehension in exec with empty locals: NameError

How to use globals()[] within a class

Variables scope and order of exec

Python: exec in local scope

Is it possible to access exec-provided globals dictionary from within a function?

Why does Python 3 exec() fail when specifying locals?

How to use functions in globals variables in ejs/express?