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

491 投票
14 回答
507235 浏览
提问于 2025-04-15 11:04

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


编辑提示:绝对不要对可能来自程序外部的数据使用eval(或exec)。这会带来严重的安全风险。因为这样你就允许数据的作者在你的电脑上运行任意代码。如果你来这里是想在Python程序中按照某种模式创建多个变量,你几乎肯定遇到了一个XY问题。其实根本不需要创建那些变量,可以适当地使用列表或字典

14 个回答

40

evalexec 是正确的解决方案,而且可以用更安全的方式来使用。

正如在 Python的参考手册 中讨论的,以及在 这个教程中清楚解释的,evalexec 函数有两个额外的参数,可以让用户指定哪些全局和局部的函数和变量是可用的。

举个例子:

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()

撰写回答