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


357

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


5
公平地说,与另一个问题不同,这个问题不是重复的。其他人则发布了比这更多的基本问题。
DNS

8
当然,正确的答案几乎总是“不要!”。
2009年

23
@S。Lott:最近没看过FAQ吗?“问和回答自己的编程问题也很好,但假装您正处于危险之中:以问题的形式表达它”。这不是一个坏问题。+1
Devin Jeanpierre 2009年

49
@ S.Lott:不。不用了 如果问题不在站点上,那么这是一个公平的游戏(根据FAQ,正如已经指出的那样)。只需回答每个问题,就好像OP需要帮助。他们可能不会,但是下一个读他们的问题的人可能会。只是我的2美分。
比尔蜥蜴

1
所有人都说不要这样做:我有一个绝对需要的情况。它涉及分布式处理。
sudo

Answers:


331

对于语句,请使用exec(string)(Python 2/3)或exec string(Python 2):

>>> mycode = 'print "hello world"'
>>> exec(mycode)
Hello world

当需要表达式的值时,请使用eval(string)

>>> x = eval("2+2")
>>> x
4

但是,第一步应该是问自己是否真的需要。通常,执行代码应该是最后的选择:如果代码中可能包含用户输入的代码,则它很慢,很丑陋而且很危险。您应该始终首先考虑替代项,例如高阶函数,以查看它们是否可以更好地满足您的需求。


1
但是'exec'执行的代码范围如何?是嵌套的吗?
jondinham 2012年

21
某人想要使用'exec'的常见情况是诸如if s=='foo': x.foo = 42 elif s=='bar': x.bar = 42etc之类的东西,然后他们可能写成exec ("x.%s = 42" % s)。对于这种常见情况(您只需要访问存储在字符串中的对象的属性),就会有一个更快,更干净和更安全的功能getattr:只写getattr(x, s) = 42同样的意思。
ShreevatsaR 2012年

5
exec如何比python解释器慢?
Cris Stringfellow

6
@ShreevatsaR不是setattr(x, s, 42)吗?我尝试过getattr(x, 2) = 42但失败了can't assign to function call: <string>, line 1
Tanner Semerad 2013年

6
@坦纳:嗯。是的,确实setattr(x, s, 42)是正确的语法。很惊讶花了这么长时间才发现该错误。无论如何,问题是,getattrsetattr对替代exec时,所有你想要的是得到一个任意成员,抬头的字符串。
ShreevatsaR 2013年

68

在示例中,使用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()

1
这样换掉stdout和stderr让我非常紧张。这看起来可能会引起巨大的安全问题。有办法解决吗?
Narcolapser

1
@Narcolapser,您应该更加关心使用exec(除非您知道代码字符串来自受信任的来源)。
bruno desthuilliers

27

eval并且exec是正确的解决方案,它们可以被用在更安全方式。

正如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

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


9
确保评估安全是不可能的: 评估确实很危险。如果您从我这里获取代码并进行评估,我可以对您的Python程序进行隔离。游戏结束。
Ned Batchelder

3
@ v.oddou我在回应alan的声明:“可以安全地使用eval和exec ..”。这是错误的。如果有人说“可以安全地使用bash”,那也将是错误的。重击很危险。这是必要的危险,但仍然很危险。声称可以使评估安全是完全错误的。
Ned Batchelder 2015年

1
@NedBatchelder确实是。您指向的链接是很好的材料。权力伴随着责任,所以重点只是要了解评估的潜在权力。如果我们认为力量=危险。
v.oddou

3
@NedBatchelder用Python编写的许多代码也可能很危险,但是为什么要假设evalexec打算用作代码exec(input("Type what you want"))呢?在许多情况下,程序可能会由于计算而编写过程或函数;产生的功能将与良好且编写良好的程序的任何其他部分一样安全,快捷(一旦评估)。包含不安全程序的exec危险并不比不安全程序本身造成损害的危险更大,因为exec它不会赋予程序任何新的特权。
Thomas Baruchel

1
再次@ThomasBaruchel,我的观点是反对可以使eval或exec安全的观点。特别是,此答案声称,控制全局变量和本地变量将使其可以安全地使用它们。那是错误的。每当您使用exec和eval时,您都必须确切地知道正在执行什么代码。如果您不这样做,那么您很容易遭受危险的操作。
Ned Batchelder

21

请记住,从版本3开始exec是一个功能!
因此请始终使用exec(mystring)代替exec mystring


11

eval()仅用于表达,虽然eval('x+1')有效,但eval('x=1')不会起作用。在这种情况下,最好使用exec,甚至更好:尝试找到更好的解决方案:)


11

避免execeval

在Python中使用execeval受到了极大的反对。

有更好的选择

从最上面的答案(强调我的):

对于语句,请使用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(重点是我的)

因此,即使您删除了所有的全局变量和内置函数,eval也不安全!

所有这些尝试保护eval()的问题都在于它们是黑名单。他们明确删除了可能危险的内容。那是一场失败的战斗,因为如果只剩下一个项目,那么您可以攻击系统

那么,可以使eval安全吗?很难说。在这一点上,我最好的猜测是,如果您不能使用任何双下划线,那么不会造成任何伤害,因此,如果您排除任何具有双下划线的字符串,那么您是安全的。也许...

很难阅读和理解

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

首先,exec使人类更难阅读您的代码。为了弄清楚发生了什么,我不仅要阅读您的代码,还必须阅读您的代码,弄清楚它将生成什么字符串,然后阅读该虚拟代码。因此,如果您在团队中工作,发布开源软件或在StackOverflow之类的地方寻求帮助,那么其他人将很难为您提供帮助。而且,如果您有机会在6个月后进行该代码的调试或扩展,那么直接给自己增加难度。


“我最大的猜测是,如果您不能使用任何双下划线,那么就不会造成任何伤害。”-您可以构造一个包含双下划线的字符串,然后调用该字符串。
斯坦利·巴克

好的建议,除非您正在编写代码生成器,求职者或类似的工具……这里的大多数人可能正在这样做。
Erik Aronesty,

我必须从config-file(cfg.yaml)中导入相对路径:reldir : ../my/dir/ reldir = cfg[reldir]。但是,由于此python代码将同时在Windows和Linux上运行,因此我需要进行调整以适应不同的操作系统路径分隔符。无论是\\ /。所以我reldir : os.path.join('..','my','dir')在配置文件中使用。但这只会导致reldir该字符串成为文字字符串,而不会被评估,因此无法在中打开文件reldir。你有什么建议吗?
玛丽。P.

9

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

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

4

1
这在普通的python中不起作用。在蟒蛇3.至少不
托马斯AHLE

6

正如其他人提到的那样,它是“ exec” ..

但是,如果您的代码包含变量,则可以使用“全局”来访问它,还可以防止编译器引发以下错误:

NameError:名称“ p_variable”未定义

exec('p_variable = [1,2,3,4]')
global p_variable
print(p_variable)


4

值得一提的是,如果您要调用python文件,则该exec兄弟也存在execfile。如果您使用的第三方程序包中包含糟糕的IDE,并且您想在其程序包之外进行编码,那有时会很好。

例:

execfile('/path/to/source.py)'

要么:

exec(open("/path/to/source.py").read())



1

我尝试了很多事情,但是唯一可行的事情如下:

temp_dict = {}
exec("temp_dict['val'] = 10") 
print(temp_dict['val'])

输出:

10


0

最合乎逻辑的解决方案是使用内置的eval()函数。另一种解决方案是将该字符串写入临时python文件并执行。


0

好吧..我知道这不是一个确切的答案,但可能是对像我一样看这个问题的人的注释。我想为不同的用户/客户执行特定的代码,但也想避免执行/评估。我最初希望将代码存储在每个用户的数据库中,然后执行上述操作。

我最终在“ customer_filters”文件夹中的文件系统上创建了文件,并使用了“ imp”模块,如果没有针对该客户应用的过滤器,它将继续进行

import imp


def get_customer_module(customerName='default', name='filter'):
    lm = None
    try:
        module_name = customerName+"_"+name;
        m = imp.find_module(module_name, ['customer_filters'])
        lm = imp.load_module(module_name, m[0], m[1], m[2])
    except:
        ''
        #ignore, if no module is found, 
    return lm

m = get_customer_module(customerName, "filter")
if m is not None:
    m.apply_address_filter(myobj)

因此,customerName =“ jj”将执行customer_filters \ jj_filter.py文件中的apply_address_filter


1
您如何管理安全性?您如何知道客户不会滥用此特权?
JSBach
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.