ChatGPT解决这个技术问题 Extra ChatGPT

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

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

公平地说,与其他问题不同,这个问题不是重复的。其他人发布了比这更多的基本问题。
当然,正确的答案几乎总是“不要!”。
@S。 Lott:最近没有阅读常见问题解答吗? “问和回答你自己的编程问题也很好,但假装你在危险中:以问题的形式表达它”。这不是一个坏问题。 +1
@S.Lott:你没有。你不需要。如果问题不在网站上,那么这是公平的游戏(根据常见问题解答,正如已经指出的那样)。只需回答每个问题,就好像 OP 需要帮助一样。他们可能不会,但下一个阅读他们问题的人可能会。只是我的2美分。
对于所有你说不要这样做的人:我有一个我绝对需要这样做的案例。它涉及分布式处理。

H
Helen

对于语句,请使用 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

但是,第一步应该是问问自己是否真的需要。执行代码通常应该是不得已的位置:如果它可以包含用户输入的代码,它会变得缓慢、丑陋和危险。您应该始终首先查看替代方案,例如高阶函数,看看它们是否能更好地满足您的需求。


但是'exec'执行的代码的范围呢?它是嵌套的吗?
某人想要使用 'exec' 的常见情况是 if s=='foo': x.foo = 42 elif s=='bar': x.bar = 42 等,然后他们可以将其写为 exec ("x.%s = 42" % s)。对于这种常见情况(您只需要访问存储在字符串中的对象的属性),有一个更快、更清晰、更安全的函数 getattr:只需写 getattr(x, s) = 42 来表示相同的意思。
exec 比 python 解释器慢多少?
@ShreevatsaR 你不是说setattr(x, s, 42)吗?我尝试了 getattr(x, 2) = 42,但以 can't assign to function call: <string>, line 1 失败
@Tanner:嗯。是的,确实 setattr(x, s, 42) 是正确的语法。令人惊讶的是花了这么长时间才发现这个错误。无论如何,关键是 getattrsetattrexec 的替代品,当您想要获取任意成员时,通过字符串查找。
h
hekevintran

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

像这样交换 stdout 和 stderr 让我非常紧张。这看起来可能会导致巨大的安全问题。有办法解决吗?
@Narcolapser 您应该更关心使用 exec (除非您知道代码字符串来自受信任的来源)。
S
Sergey Orshanskiy

evalexec 是正确的解决方案,它们可以以更安全的方式使用。

Python's reference manual 中所述并在 this 教程中明确解释,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

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


无法使 eval 安全:Eval really is dangerous。如果您从我这里获取代码并对其进行评估,我可以对您的 Python 程序进行分段。游戏结束。
@v.oddou 我正在回应艾伦的声明,“eval 和 exec .. 可以以安全的方式使用。”这是错误的。如果有人说“bash 可以以安全的方式使用”,那也是错误的。巴什是危险的。这是必要的危险,但仍然很危险。声称 eval 可以变得安全是完全错误的。
@NedBatchelder 确实是的。你指向的链接是很好的材料。权力伴随着责任,所以关键是要意识到 eval 的潜在力量。如果我们决定权力=危险。
@NedBatchelder 许多用 Python 编写的代码也可能很危险,但是您为什么假设 evalexec 打算用作 exec(input("Type what you want"))?在很多情况下,程序可能会根据计算结果编写过程或函数。生成的函数将与编写良好的程序的任何其他部分一样安全和快速(一旦评估)。 包含 exec 的不安全程序并不比不安全程序本身造成的损害更危险,因为 exec 不会赋予程序任何新的特权。
@ThomasBaruchel 再次,我的观点是反驳 eval 或 exec 可以变得安全的概念。特别是,这个答案声称控制全局变量和局部变量将使安全使用它们成为可能。那是错误的。每当您使用 exec 和 eval 时,您都必须准确地知道正在执行的代码。如果你不这样做,那么你就有可能面临危险的操作。
R
Remi Guan

请记住,从版本 3 开始,exec 是一个函数!
因此请始终使用 exec(mystring) 而不是 exec mystring


C
Community

避免执行和评估

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

有更好的选择

从最佳答案(强调我的):

对于语句,请使用 exec。当您需要表达式的值时,请使用 eval。但是,第一步应该是问问自己是否真的需要。执行代码通常应该是不得已的位置:如果它可以包含用户输入的代码,它会变得缓慢、丑陋和危险。您应该始终首先查看替代方案,例如高阶函数,看看它们是否能更好地满足您的需求。

来自Alternatives to 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 个月后调试或扩展此代码,那么您将直接让自己变得更加困难。


“我最好的猜测是,如果你不能使用任何双下划线,你就不会造成任何伤害” - 你可以构造一个包含双下划线的字符串,然后调用 eval 该字符串。
好的建议,除非您正在编写代码生成器、工作运行程序或类似的东西……这里的大多数人可能正在这样做。
我必须从配置文件 (cfg.yaml) 导入相对路径:reldir : ../my/dir/ reldir = cfg[reldir]。但是,由于这个 python 代码应该在 Windows 和 Linux 上运行,我需要它来适应不同的操作系统路径分隔符; \\ /。所以我在配置文件中使用了 reldir : os.path.join('..','my','dir')。但这只会导致 reldir 成为这个文字字符串,而不是被评估,所以我无法在 reldir 中打开文件。你有什么建议吗?
嗯,没有。这些是高度pythonic。你认为 REPL 是什么?
J
Jérôme Verstrynge

eval() 仅用于表达式,而 eval('x+1') 有效,例如 eval('x=1') 无效。在这种情况下,最好使用 exec,甚至更好:尝试找到更好的解决方案 :)


u
user1767754

值得一提的是,'exec 的兄弟存在,如果你想调用一个 python 文件,它也被称为 execfile。如果您正在使用包含糟糕 IDE 的第三方包并且您想在其包之外进行编码,这有时会很好。

例子:

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

或者:

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


“IDE”即“文本编辑器”?你不是说“API?
o
octopusgrabbus

您可以使用 exec 完成代码的执行,如以下 IDLE 会话:

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

4

这在普通 python 中不起作用。至少在 python 3 中没有。
M
Minions

正如其他人提到的,它是“执行” ..

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

NameError:名称“p_variable”未定义

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

p
paul-shuvo

我尝试了很多东西,但唯一有效的是以下内容:

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

输出:

10


在尝试了上述大多数方法之后,这是唯一有效的方法。格拉西亚斯
P
Pablo Santa Cruz

使用 eval


Eval() 不执行语句。
r
ryeguy

查看eval

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

Eval() 不执行语句。
J
John T

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


B
Brian

好的..我知道这不完全是一个答案,但可能是给像我一样看这个的人的注释。我想为不同的用户/客户执行特定的代码,但也想避免 exec/eval。我最初希望为每个用户将代码存储在数据库中并执行上述操作。

我最终在“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


你是如何管理安全的?你怎么知道客户不会滥用这个特权?