I'm trying to use Python's exec
in a project to execute embedded Python code.
The problem I've encountered is that variables created at the module-level in an exec
statement are inaccessible from functions defined in the same module.
Let's say you have the following Python program:
x = 5
def foo():
print x
foo()
If you put the above four lines in a file and ran it, it would work no problemo.
However, if you try running this same piece of code from within an exec
statement, it won't work.
Here's our previous program, inside an exec
statement:
import __builtin__
global_env = {'__builtins__': __builtin__}
local_env = dict()
exec """
x = 5
def foo():
print x
foo()
""" in global_env, local_env
On execution, instead of working, it yields the following error:
Traceback (most recent call last):
File "lab.py", line 94, in <module>
""" in global_env, local_env
File "<string>", line 5, in <module>
File "<string>", line 4, in foo
NameError: global name 'x' is not defined
I thought module-level variables were stored globally, but it seems that, at least in exec
, they're not.
For example, in the previous example, if you replace the call to foo()
with:
print global_env
print local_env
You get:
{'__builtins__': <module '__builtin__' (built-in)>}
{'x': 5, 'foo': <function foo at 0x102c12938>}
So anything defined in the module-level (including x
) is stored in locals()
.
But it's impossible to access x
from anywhere except the module-level (of the exec
statement). In particular, as we saw above, the local scope of x
is invisible to functions defined in the same exec
statement.
Workarounds
I've found two ways to workaround this issue, and make x
accessible again.
The first one is using the global
keyword in the function:
exec """
x = 5
def foo():
global x
print x
foo()
""" in global_env, local_env
The second one is using the same dictionary for globals()
and locals()
in exec
:
exec """
x = 5
def foo():
print x
foo()
""" in global_env
However, these are just half-fixes/workarounds that don't address the original issue.
So my questions are: Why are module-level variables in an exec
stored locally, and why are inaccessible from anywhere but the module-level?
Some closely related StackOverflow posts: