【问题标题】:How to run a large amount of python code from a string?如何从字符串中运行大量 python 代码?
【发布时间】:2013-04-14 22:20:32
【问题描述】:

我需要能够从字符串中运行大量 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

我尝试运行的代码可在第一个代码 sn-p 中的链接中找到。

如果您有任何问题,我会回答。谢谢。

【问题讨论】:

  • 您可能需要考虑一下这种设计的安全隐患。
  • 就 NPE 而言,考虑 PyPy 的 sandboxing 功能可能会很有用。
  • 补充 NPE 的观点,请注意 urllib 文档中的这一点:When opening HTTPS URLs, it does not attempt to validate the server certificate. Use at your own risk! 换句话说,中间人攻击是可能的,这种设计将允许攻击者执行任意代码在您的系统上。
  • 考虑到我打算使用它的方式是编写它链接到我自己的代码,将其托管在保管箱上并将此代码作为可执行文件提供,这仍然是一个问题。 (从而使更新代码更容易)。
  • 应该可以的。你遇到了什么错误?

标签: python url python-3.x exec dropbox


【解决方案1】:

在不指定全局变量的情况下,exec function (Python/bltinmodule.c) 使用 PyEval_GetGlobals()PyEval_GetLocals()。对于函数的执行帧,后者创建一个新的f_locals dict,它将作为编译代码中IMPORT_NAMESTORE_NAMELOAD_NAME 操作的目标。

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

解决方案是手动提供globalsexec 也将用作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 的安全问题仍然适用。我只是解决命名空间的技术问题。

【讨论】:

    【解决方案2】:

    首先我想你可以试试 __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() 的结果。

    【讨论】:

    • __import__ 将模块名称作为参数。您链接到的问题使用StringIO 作为要导入的模块的示例。
    • 是的,我现在明白了;希望尽快解决这个问题(使用imp 模块)。
    【解决方案3】:

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

    谷歌os.popensubprocess.Popen

    【讨论】:

    • 这似乎引发了一个不同的错误FileNotFoundError: [WinError 2] The system cannot find the file specified
    • 您不必将代码字符串放入文件中。你只需要启动一个 python 子进程并将代码字符串写入它的 pipe.stdin。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-26
    • 1970-01-01
    • 2017-02-21
    • 1970-01-01
    • 2023-03-04
    • 2010-10-16
    相关资源
    最近更新 更多