如何在Python中执行包含Python代码的字符串?
我该如何在Python中执行包含Python代码的字符串呢?
编辑提示:绝对不要对可能来自程序外部的数据使用eval
(或exec
)。这会带来严重的安全风险。因为这样你就允许数据的作者在你的电脑上运行任意代码。如果你来这里是想在Python程序中按照某种模式创建多个变量,你几乎肯定遇到了一个XY问题
。其实根本不需要创建那些变量,可以适当地使用列表或字典。
14 个回答
40
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
本质上,你是在定义代码执行的命名空间。
466
对于语句,可以使用 exec(string)
(Python 3)或者 exec string
(Python 2):
>>> my_code = 'print("Hello world")'
>>> exec(my_code)
Hello world
当你需要一个表达式的值时,可以使用 eval(string)
:
>>> x = eval("2+2")
>>> x
4
不过,首先要问问自己,真的有必要这样做吗?执行代码通常是最后的选择:它速度慢,效果不好,而且如果代码中包含用户输入的内容,可能会很危险。你应该先考虑其他的选择,比如更高阶的函数,看看这些是否能更好地满足你的需求。
85
在这个例子中,使用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()