Reputation: 43
I have a file named file.py
containing the following script:
def b():
print("b")
def proc():
print("this is main")
b()
proc()
And I have another file named caller.py
, which contains this script:
text = open('file.py').read()
exec(text)
When I run it, I get the expected output:
this is main
b
However, if I change caller.py
to this:
def main():
text = open('file.py').read()
exec(text)
main()
I get the following error:
this is main
Traceback (most recent call last):
File "./caller.py", line 7, in <module>
main()
File "./caller.py", line 5, in main
exec(text)
File "<string>", line 10, in <module>
File "<string>", line 8, in main
NameError: global name 'b' is not defined
How is function b()
getting lost? It looks to me like I'm not violating any scope rules. I need to make something similar to the second version of caller.py
work.
Upvotes: 4
Views: 103
Reputation: 33719
exec(text)
executes text
in the current scope, but modifying that scope (as def b
does via the implied assignment) is undefined.
The fix is simple:
def main():
text = open('file.py').read()
exec(text, {})
This causes text
to run in an empty global scope (augmented with the default __builtins
object), the same way as in a regular Python file.
For details, see the exec
documentation. It also warns that modifying the default local scope (which is implied when not specifying any arguments besides text
) is unsound:
The default locals act as described for function
locals()
below: modifications to the default locals dictionary should not be attempted. Pass an explicit locals dictionary if you need to see effects of the code on locals after functionexec()
returns.
Upvotes: 3
Reputation: 1235
Would it work for you if you imported and called the function instead?
myfile.py
def b():
print("b")
def proc():
print("this is main")
b()
caller.py
import myfile
myfile.proc()
Upvotes: 1