2

我需要能够从字符串中运行大量 python 代码。简单地使用exec似乎不起作用,因为虽然代码在正常设置下完美运行,但这样做似乎会引发错误。我也不认为我可以将它导入它,因为它托管在互联网上。这是代码:

import urllib.request

URL = "https://dl.dropboxusercontent.com/u/127476718/instructions.txt"  

def main():
    instructions = urllib.request.urlopen(URL)

    exec(instructions.read().decode())

if __name__ == "__main__":
    main()

这是我得到的错误:

Traceback (most recent call last):
  File "C:\Python33\rc.py", line 12, in <module>
    main()
  File "C:\Python33\rc.py", line 9, in main
    exec(instructions.read().decode())
  File "<string>", line 144, in <module>
  File "<string>", line 120, in main
NameError: global name 'Player' is not defined

我尝试运行的代码可在第一个代码片段的链接中找到。

如果你有任何问题,我会回答他们。谢谢你。

4

3 回答 3

3

在不指定全局变量的情况下,exec函数(Python/bltinmodule.c) 使用PyEval_GetGlobals()and PyEval_GetLocals()。对于函数的执行帧,后者会创建一个新的f_localsdict,它将成为编译代码中IMPORT_NAME, STORE_NAME, ops 的目标。LOAD_NAME

在 Python 的模块级别,正常情况是globals() == locals(). 在这种情况下STORE_NAME,使用模块的全局变量,这是在模块中定义的函数将用作其全局命名空间。但是,对全局变量和局部变量使用单独的 dicts 显然打破了这一假设。

解决方案是手动提供globals,这exec也将用作locals

def main():
    instructions = urllib.request.urlopen(URL)
    exec(instructions.read().decode(), globals())

您还可以使用已__name__定义的新字典:

def main():
    instructions = urllib.request.urlopen(URL)
    g = {'__name__': '__main__'}
    exec(instructions.read().decode(), g)

我在源代码中看到当前目录需要一个名为“pickup.wav”的声音文件,否则你只会得到另一个错误。

当然,关于exec像这样使用的安全问题的评论仍然适用。我只是在解决命名空间的技术问题。

于 2013-04-14T13:53:01.693 回答
1

首先,我认为您可以尝试__import__使用 StringIO 对象。可能看起来像StackOverflow: Local Import Statements in Python

……但这是不对的。

然后我想到了使用该imp模块,但这也不起作用。

然后我查看了:Alex Martelli 对Use of Eval in Python的回答——并尝试自己在一段愚蠢的代码上使用它。

我可以获取ast对象,以及从中获取的结果compile()(尽管如果您愿意,似乎也可以简单地调用compile(some_string_containing_python_source, 'SomeName', 'exec')而无需通过ast.parse()中间步骤。从我收集的内容来看,ast如果您想遍历结果语法,您会使用树,在编译之前检查并可能修改节点。

最后,在执行命名空间中定义结果函数、类或变量之前,您似乎需要exec()得到结果。compile()

于 2013-04-14T09:38:38.417 回答
0

您可以使用pipe将所有字符串放入 python 的子进程并从中获取输出结果。

谷歌os.popensubprocess.Popen

于 2013-04-14T09:03:39.677 回答