在线程中使用 exec(compile()) 导入问题
import issue using exec(compile()) in thread
Windows 10,Python 这里是 3.5.1 x64。
这很奇怪...假设我有这个脚本,叫做 do.py
。请注意 import string
语句:
import string
# Please note that if the print statement is OUTSIDE 'main()', it works.
# It's like if 'main()' can't see the imported symbols from 'string'
def main():
print(string.ascii_lowercase)
main()
我想在子线程中从 "launcher script" 中 运行 它,像这样 (launcher.py
):
import sys
import threading
sys.argv.append('do.py')
def run(script, filename):
exec(compile(script, filename, 'exec'))
with open(sys.argv[1], 'rb') as _:
script = _.read()
# But this WORKS:
# exec(compile(script, sys.argv[1], 'exec'))
thread = threading.Thread(name='Runner', target=run, args=(script, sys.argv[1]))
thread.start()
thread.join()
它死于以下错误:
Exception in thread Runner:
Traceback (most recent call last):
File "C:\Program Files\Python35\lib\threading.py", line 914, in _bootstrap_inner
self.run()
File "C:\Program Files\Python35\lib\threading.py", line 862, in run
self._target(*self._args, **self._kwargs)
File "tmpgui.py", line 7, in run
exec(compile(script, filename, 'exec'))
File "do.py", line 6, in <module>
main()
File "do.py", line 4, in main
print(string.ascii_lowercase)
NameError: name 'string' is not defined
也就是说,执行的代码没有正确导入 string
或类似的东西,并且在 main()
中 string
模块不可见。
这不是我的项目的完整代码,它太大了 post 这里,但我创建的模拟问题的最低限度。
以防万一有人好奇,我正在重写我的一个旧程序,它导入了脚本的 main()
函数和 运行 函数,标准输出流重定向到 tkinter
文本框。我不想从脚本中导入函数,而是想加载脚本并 运行 它。我不想使用 subprocess
出于各种原因,我更喜欢 运行 线程中的 "redirected" 代码并与处理 GUI 的主线程通信.那部分工作得很好,我唯一的问题是这个,我不明白为什么会这样!
我最好的选择:我应该将全局或本地字典中的内容传递给 exec
,但我在这里迷路了...
非常感谢!
exec(thing)
等价于 exec(thing, globals(), locals())
.
因此,
- 的局部符号tabledo.py是
run
函数的局部符号table
- do.py的全局符号table是launcher.py[的全局符号table
import string
导入模块并绑定到本地space中的变量,也就是run
函数的本地space。您可以验证这一点:
def run(script, filename):
try:
exec(compile(script, filename, 'exec'))
finally:
assert 'string' in locals(), "won't fail because 'import' worked properly"
main
有一个单独的本地作用域,但它与 do.py 共享全局符号 table,因此与 launcher.py.
Python 试图在 main
的局部(它是空的)和全局符号 table 中找到名为 string
的变量,但失败了,并引发了NameError
.
在对 exec
的调用中传递一个空字典:
def run(script, filename):
exec(compile(script, filename, 'exec'), {})
Windows 10,Python 这里是 3.5.1 x64。
这很奇怪...假设我有这个脚本,叫做 do.py
。请注意 import string
语句:
import string
# Please note that if the print statement is OUTSIDE 'main()', it works.
# It's like if 'main()' can't see the imported symbols from 'string'
def main():
print(string.ascii_lowercase)
main()
我想在子线程中从 "launcher script" 中 运行 它,像这样 (launcher.py
):
import sys
import threading
sys.argv.append('do.py')
def run(script, filename):
exec(compile(script, filename, 'exec'))
with open(sys.argv[1], 'rb') as _:
script = _.read()
# But this WORKS:
# exec(compile(script, sys.argv[1], 'exec'))
thread = threading.Thread(name='Runner', target=run, args=(script, sys.argv[1]))
thread.start()
thread.join()
它死于以下错误:
Exception in thread Runner:
Traceback (most recent call last):
File "C:\Program Files\Python35\lib\threading.py", line 914, in _bootstrap_inner
self.run()
File "C:\Program Files\Python35\lib\threading.py", line 862, in run
self._target(*self._args, **self._kwargs)
File "tmpgui.py", line 7, in run
exec(compile(script, filename, 'exec'))
File "do.py", line 6, in <module>
main()
File "do.py", line 4, in main
print(string.ascii_lowercase)
NameError: name 'string' is not defined
也就是说,执行的代码没有正确导入 string
或类似的东西,并且在 main()
中 string
模块不可见。
这不是我的项目的完整代码,它太大了 post 这里,但我创建的模拟问题的最低限度。
以防万一有人好奇,我正在重写我的一个旧程序,它导入了脚本的 main()
函数和 运行 函数,标准输出流重定向到 tkinter
文本框。我不想从脚本中导入函数,而是想加载脚本并 运行 它。我不想使用 subprocess
出于各种原因,我更喜欢 运行 线程中的 "redirected" 代码并与处理 GUI 的主线程通信.那部分工作得很好,我唯一的问题是这个,我不明白为什么会这样!
我最好的选择:我应该将全局或本地字典中的内容传递给 exec
,但我在这里迷路了...
非常感谢!
exec(thing)
等价于 exec(thing, globals(), locals())
.
因此,
- 的局部符号tabledo.py是
run
函数的局部符号table - do.py的全局符号table是launcher.py[的全局符号table
import string
导入模块并绑定到本地space中的变量,也就是run
函数的本地space。您可以验证这一点:
def run(script, filename):
try:
exec(compile(script, filename, 'exec'))
finally:
assert 'string' in locals(), "won't fail because 'import' worked properly"
main
有一个单独的本地作用域,但它与 do.py 共享全局符号 table,因此与 launcher.py.
Python 试图在 main
的局部(它是空的)和全局符号 table 中找到名为 string
的变量,但失败了,并引发了NameError
.
在对 exec
的调用中传递一个空字典:
def run(script, filename):
exec(compile(script, filename, 'exec'), {})