运行包含在字符串中的Python代码

时间:2009-06-18 20:55:33

标签: python pygame exec eval

我正在使用pygame和box2d编写游戏引擎,在角色构建器中,我希望能够编写将在keydown事件上执行的代码。

我的计划是在角色构建器中安装一个文本编辑器,让您编写类似于:

的代码
if key == K_a:
    ## Move left
    pass
elif key == K_d:
    ## Move right
    pass

我将检索文本编辑器的内容作为字符串,我希望代码在这个Character方法的方法中运行:

def keydown(self, key):
    ## Run code from text editor

最好的方法是什么?

4 个答案:

答案 0 :(得分:25)

您可以使用eval(string)方法执行此操作。

定义

eval(code, globals=None, locals=None)
代码只是标准的Python代码 - 这意味着它仍然需要正确缩进。

全局变量可以定义自定义__builtins__,这可能对安全性有用。

实施例

eval("print('Hello')")

hello打印到控制台。您还可以为要使用的代码指定本地和全局变量:

eval("print('Hello, %s'%name)", {}, {'name':'person-b'})

安全问题

但是,要小心。将执行任何用户输入。考虑:

eval("import os;os.system('sudo rm -rf /')")

有很多方法可以解决这个问题。最简单的方法是做:

eval("import os;...", {'os':None})

这将抛出异常,而不是擦除您的硬盘。虽然你的程序是桌面的,但如果人们重新分发脚本,这可能是一个问题,我想这是有意的。

奇怪的例子

以下是使用eval的一个例子:

def hello() : print('Hello')
def world() : print('world')
CURRENT_MOOD = 'happy'

eval(get_code(), {'contrivedExample':__main__}, {'hi':hello}.update(locals()))

这对评估线的作用是:

  1. 为当前模块提供另一个名称(它变为contrivedExample到脚本中)。消费者现在可以致电contrivedExample.hello()。)
  2. 它将hi定义为指向hello
  3. 它将该字典与执行模块中的当前全局变量列表相结合。
  4. FAIL

    事实证明(感谢评论者!)您确实需要使用exec语句。大哎呀。修改后的例子如下:


    exec定义

    (看起来很熟悉!) Exec是一个声明:
    exec "code" [in scope] 范围是本地和全局变量的字典。如果未指定,则在当前范围内执行。

    代码只是标准的Python代码 - 这意味着它仍然需要正确缩进。

    exec示例

    exec "print('hello')"
    

    hello打印到控制台。您还可以为要使用的代码指定本地和全局变量:

    eval "print('hello, '+name)" in {'name':'person-b'}
    

    exec安全问题

    但是,要小心。将执行任何用户输入。考虑:

    exec "import os;os.system('sudo rm -rf /')"
    

    打印声明

    评论者也指出,print是3.0之前所有Python版本的声明。在2.6中,可以通过键入from __future__ import print_statement来更改行为。否则,请使用:

    print "hello"
    

    而不是:

    print("hello")
    

答案 1 :(得分:2)

正如其他人所指出的那样,您可以将文本加载到字符串中并使用exec "codestring"。如果已包含在文件中,则使用execfile将无需加载它。

一个性能注释:您应该避免多次执行代码,因为解析和编译python源是一个缓慢的过程。即。没有:

def keydown(self, key):
    exec user_code

你可以通过将源代码编译成代码对象(使用compile()和exec来改进这一点,或者更好,通过构造一个你保留的函数,并且只构建一次。要么用户要么写“def my_handler(args ...)”,或者自己添加,然后执行以下操作:

user_source = "def user_func(args):\n" + '\n'.join("    "+line for line in user_source.splitlines())

d={}
exec user_source in d
user_func = d['user_func']

然后:

if key == K_a:
   user_func(args)

答案 2 :(得分:0)

您可以使用eval()

答案 3 :(得分:0)

eval或exec。在编程之前,你一定要阅读Python库参考。