I have a file data.py
in directory exectest
containing
testd = { 1: "one", 2: "two" }
When I type import data
, I get
In [5]: import data
In [6]: data.testd
Out[6]: {1: 'one', 2: 'two'}
as expected. However, I have another file exectest.py
containing
from pathlib import Path
def read_data():
path = Path.cwd() / "data.py"
text = path.read_text()
print(f"{text=}")
exec(text)
return testd
When I type the following, I get an error
In [7]: exectest.read_data()
text='\ntestd = { 1: "one", 2: "two" }\n'
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[7], line 1
----> 1 exectest.read_data()
File ~/working/tmp/exectest/exectest.py:9, in read_data()
7 print(f"{text=}")
8 exec(text)
----> 9 return testd
NameError: name 'testd' is not defined
From the interpreter, typing in the statements in read_data()
directly reads the text in data.py
and evaluates it correctly,
In [10]: from pathlib import Path
In [11]: path = Path.cwd() / "data.py"
In [12]: text = path.read_text()
In [13]: text
Out[13]: '\ntestd = { 1: "one", 2: "two" }\n'
In [14]: exec(text)
In [15]: testd
Out[15]: {1: 'one', 2: 'two'}
I don't understand why import data
works, and typing statements directly into the interpreter works, but packaging those statements up into a function does not. Any ideas?
The variables created inside an exec
call are by default local to the scope of that exec
call. They do not become global variables, which is why you're encountering a NameError
when trying to access testd outside of the exec call.
You can pass a locals dictionary to the exec function like so:
from pathlib import Path
def read_data():
path = Path.cwd() / "data.py"
text = path.read_text()
print(f"{text=}")
local_vars = {}
exec(text, {}, local_vars)
testd = local_vars.get('testd', None)
return testd