Python的eval()做什么?

问题描述 投票:252回答:10

在我正在阅读Python的书中,它继续使用代码eval(input('blah'))

我阅读了文档,我理解它,但我仍然没有看到它如何改变input()函数。

它有什么作用?谁能解释一下?

python eval
10个回答
230
投票

eval函数允许Python程序在其自身内部运行Python代码。

eval示例(交互式shell):

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

2
投票

如果要将评估字符串限制为简单文字,另一个选项是使用ast.literal_eval()。一些例子:

import ast

# print(ast.literal_eval(''))          # SyntaxError: unexpected EOF while parsing
# print(ast.literal_eval('a'))         # ValueError: malformed node or string
# print(ast.literal_eval('import os')) # SyntaxError: invalid syntax
# print(ast.literal_eval('1+1'))       # 2: but only works due to a quirk in parser
# print(ast.literal_eval('1*1'))       # ValueError: malformed node or string
print(ast.literal_eval("{'a':1}"))     # {'a':1}

来自docs

安全地评估表达式节点或包含Python文字或容器显示的字符串。提供的字符串或节点可能只包含以下Python文字结构:字符串,字节,数字,元组,列表,dicts,集合,布尔值和None。

这可用于安全地评估包含来自不受信任来源的Python值的字符串,而无需自己解析值。它无法评估任意复杂的表达式,例如涉及运算符或索引。

至于为什么它如此有限,来自the mailing list

允许使用文字的运算符表达式,但比当前实现复杂得多。一个简单的实现是不安全的:你可以毫不费力地引出基本无限制的CPU和内存使用(尝试“9 ** 9 ** 9”或“[None] * 9 ** 9”)。

至于有用性,这个函数对于“回读”由repr()字符串化的文字值和容器很有用。例如,这可以用于类似但比JSON更强大的格式的序列化。


141
投票

eval()将字符串解释为代码。这么多人警告你使用它的原因是因为用户可以使用它作为在计算机上运行代码的选项。如果您导入了eval(input())os,则可以输入input() os.system('rm -R *'),这将删除您主目录中的所有文件。 (假设你有一个unix系统)。使用eval()是一个安全漏洞。如果您需要将字符串转换为其他格式,请尝试使用这些内容,例如int()


42
投票

这里有很多好的答案,但没有一个描述eval()在其globalslocals kwargs(即eval(expression, globals=None, locals=None))的背景下的使用(参见eval here的文档)。

这些可用于限制通过eval方法可用的方法。例如,如果你加载一个新的python解释器,locals()globals()将是相同的,看起来像这样:

>>>globals()
{'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__doc__': None,
 '__spec__': None, '__builtins__': <module 'builtins' (built-in)>,
 '__package__': None, '__name__': '__main__'}

builtins模块中肯定有一些方法可以对系统造成重大损害。但是有可能阻止任何我们不想要的东西。我们来举个例子吧。假设我们要构建一个列表来表示系统上可用核心的域。对我来说,我有8个核心,所以我想要一个列表[1, 8]

>>>from os import cpu_count
>>>eval('[1, cpu_count()]')
[1, 8]

同样所有__builtins__都可用。

>>>eval('abs(-1)')
1

好。因此,我们看到一个我们想要暴露的方法,以及一个我们不希望暴露的方法(很多可能更复杂的方法)的例子。所以让我们阻止一切。

>>>eval('[1, cpu_count()]', {'__builtins__':None}, {})
TypeError: 'NoneType' object is not subscriptable

我们已经有效地阻止了所有__builtins__方法,因此为我们的系统带来了一定程度的保护。此时,我们可以开始添加我们想要暴露的方法。

>>>from os import cpu_count
>>>exposed_methods = {'cpu_count': cpu_count}
>>>eval('cpu_count()', {'__builtins__':None}, exposed_methods)
8
>>>eval('abs(cpu_count())', {'__builtins__':None}, exposed_methods)
TypeError: 'NoneType' object is not subscriptable

现在我们有cpu_count方法可用,同时仍然阻止我们不想要的一切。在我看来,这是超级强大的,显然是从其他答案的范围,而不是一个共同的实现。这样的东西有很多用途,只要处理得当,我个人觉得eval可以安全地用于很有价值。

注:

关于这些kwargs的其他一些很酷的事情是你可以开始使用速记代码。假设您使用eval作为管道的一部分来执行某些导入的文本。文本不需要具有确切的代码,它可以遵循一些模板文件格式,并且仍然执行您想要的任何内容。例如:

>>>from os import cpu_count
>>>eval('[1,cores]', {'__builtins__': None}, {'cores': cpu_count()})
[1, 8]

27
投票

在Python 2.x中,input(...)相当于eval(raw_input(...)),在Python 3.x中,raw_input被重命名为input,我怀疑这会导致你的混乱(你可能正在查看Python 2.x中input的文档)。另外,eval(input(...))在Python 3.x中可以正常工作,但会在Python 2中引发TypeError

在这种情况下,eval用于将从input返回的字符串强制转换为表达式并进行解释。通常这被认为是不好的做法。


6
投票

eval()将传递的字符串作为Python表达式计算并返回结果。例如,eval("1 + 1")解释并执行表达式"1 + 1"并返回结果(2)。

您可能会感到困惑的一个原因是,您引用的代码涉及一定程度的间接性。首先执行内部函数调用(输入),以便用户看到“blah”提示符。让我们假设它们以“1 + 1”响应(为了清楚起见添加了引号,在运行程序时不输入它们),输入函数返回该字符串,然后将其传递给外部函数(eval),该函数解释字符串和返回结果(2)。

阅读更多关于eval here的信息。


5
投票

也许是一个误读的例子,读取一条线并解释它。

尝试eval(input())并输入"1+1" - 这应该打印2。 Eval评估表达式。


5
投票

eval(),顾名思义,评估传递的论点。

raw_input()现在是python 3.x版本的input()。因此,最常见的使用eval()的例子是它用于提供input()在2.x版本的python中提供的功能。 raw_input将用户输入的数据作为字符串返回,而input输入评估输入的数据的值并将其返回。

因此,eval(input("bla bla"))在2.x中复制input()的功能,即评估用户输入的数据。

简而言之:eval()评估传递给它的论据,因此eval('1 + 1')返回2。


5
投票

eval()的一个有用的应用是从字符串中评估python表达式。例如从字典的文件字符串表示加载:

running_params = {"Greeting":"Hello "}
fout = open("params.dat",'w')
fout.write(repr(running_params))
fout.close()

将其作为变量读出并编辑它:

fin = open("params.dat",'r')
diction=eval(fin.read())
diction["Greeting"]+="world"
fin.close()
print diction

输出:

{'Greeting': 'Hello world'}

3
投票

我迟到了回答这个问题,但似乎没有人给出明确答案。

如果用户输入数值,input()将返回一个字符串。

>>> input('Enter a number: ')
Enter a number: 3
>>> '3'
>>> input('Enter a number: ')
Enter a number: 1+1
'1+1'

因此,eval()将评估返回值(或表达式),它是一个字符串并返回整数/浮点数。

>>> eval(input('Enter a number: '))
Enter a number: 1+1
2
>>> 
>>> eval(input('Enter a number: '))
Enter a number: 3.14
3.14

对于cource来说这是一种不好的做法。在这种情况下,应使用int()float()代替eval()

>>> float(input('Enter a number: '))
Enter a number: 3.14
3.14
© www.soinside.com 2019 - 2024. All rights reserved.