如何在Python中执行包含Python代码的字符串?


不要对可能来自程序外部的任何形式的数据使用eval(或exec)。这是一个严重的安全风险。您允许数据的作者在您的计算机上运行任意代码。如果你在这里是因为你想在你的Python程序中按照一个模式创建多个变量,你几乎肯定有一个XY问题。完全不要创建这些变量——相反,适当地使用列表或字典。


当前回答

查看eval:

x = 1
print eval('x+1')
->2

其他回答

Eval和exec是正确的解决方案,使用起来更安全。

正如Python参考手册中所讨论并在本教程中明确解释的那样,eval和exec函数接受两个额外的形参,允许用户指定可用的全局和局部函数和变量。

例如:

public_variable = 10

private_variable = 2

def public_function():
    return "public information"

def private_function():
    return "super sensitive information"

# make a list of safe functions
safe_list = ['public_variable', 'public_function']
safe_dict = dict([ (k, locals().get(k, None)) for k in safe_list ])
# add any needed builtins back in
safe_dict['len'] = len

>>> eval("public_variable+2", {"__builtins__" : None }, safe_dict)
12

>>> eval("private_variable+2", {"__builtins__" : None }, safe_dict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
NameError: name 'private_variable' is not defined

>>> exec("print \"'%s' has %i characters\" % (public_function(), len(public_function()))", {"__builtins__" : None}, safe_dict)
'public information' has 18 characters

>>> exec("print \"'%s' has %i characters\" % (private_function(), len(private_function()))", {"__builtins__" : None}, safe_dict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
NameError: name 'private_function' is not defined

实际上,您是在定义代码将在其中执行的名称空间。

你可以使用exec完成代码的执行,就像下面的IDLE会话一样:

>>> kw = {}
>>> exec( "ret = 4" ) in kw
>>> kw['ret']

4

在本例中,使用exec函数将字符串作为代码执行。

import sys
import StringIO

# create file-like string to capture output
codeOut = StringIO.StringIO()
codeErr = StringIO.StringIO()

code = """
def f(x):
    x = x + 1
    return x

print 'This is my output.'
"""

# capture output and errors
sys.stdout = codeOut
sys.stderr = codeErr

exec code

# restore stdout and stderr
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__

print f(4)

s = codeErr.getvalue()

print "error:\n%s\n" % s

s = codeOut.getvalue()

print "output:\n%s" % s

codeOut.close()
codeErr.close()

避免exec和eval

在Python中使用exec和eval是非常不受欢迎的。

有更好的选择

从最上面的答案(重点是我的):

对于语句,使用exec。 当需要表达式的值时,使用eval。 然而,第一步应该是问自己是否真的需要这样做。执行代码通常应该是最后的手段:如果它包含用户输入的代码,那么它就会变得缓慢、丑陋和危险。你应该总是先看看替代方案,比如高阶函数,看看它们是否能更好地满足你的需求。

从替代方案到exec/eval?

设置并获取字符串形式的变量的值 [eval]可以工作,但通常不建议使用对程序本身有意义的变量名。 相反,最好使用字典。

它不是惯用的

来自http://lucumr.pocoo.org/2011/2/1/exec-in-python/(我的重点)

Python不是PHP 不要试图规避Python习惯用语,因为其他语言的做法不同。命名空间在Python中是有原因的,仅仅因为它给了你exec工具,并不意味着你应该使用这个工具。

这很危险

来自http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html(我的重点)

So eval is not safe, even if you remove all the globals and the builtins! The problem with all of these attempts to protect eval() is that they are blacklists. They explicitly remove things that could be dangerous. That is a losing battle because if there's just one item left off the list, you can attack the system. So, can eval be made safe? Hard to say. At this point, my best guess is that you can't do any harm if you can't use any double underscores, so maybe if you exclude any string with double underscores you are safe. Maybe...

它很难阅读和理解

来自http://stupidpythonideas.blogspot.it/2013/05/why-evalexec-is-bad.html(我的重点):

First, exec makes it harder to human beings to read your code. In order to figure out what's happening, I don't just have to read your code, I have to read your code, figure out what string it's going to generate, then read that virtual code. So, if you're working on a team, or publishing open source software, or asking for help somewhere like StackOverflow, you're making it harder for other people to help you. And if there's any chance that you're going to be debugging or expanding on this code 6 months from now, you're making it harder for yourself directly.

查看eval:

x = 1
print eval('x+1')
->2