python的eval()做什么?

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

我读了文档,我理解它,但我仍然不明白它是如何改变input()函数的。

它能做什么?有人能解释一下吗?

498058 次浏览

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

Eval示例(交互式shell):

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

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

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

也许是一个阅读一行文字并解释它的误导性例子。

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

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

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

阅读有关eval 在这里的更多信息。

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

eval()的一个有用的应用是从string求值python表达式。例如load from file string dictionary:

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'}

eval(),顾名思义,对传递的参数求值。

raw_input()现在是python3中的input()。x版本。因此,使用eval()最常见的例子是使用它来提供input()在2中提供的功能。python的X版本。 Raw_input将用户输入的数据作为字符串返回,而input则计算输入的数据的值并返回它。< / p >

因此,eval(input("bla bla"))复制了2中input()的功能。X,即计算用户输入的数据。

简而言之:eval()计算传递给它的参数,因此eval('1 + 1')返回2。

在文档中所述,eval()也有globalslocals关键字参数,可用于限制通过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]

如果用户输入一个数值,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

但是,最好在这里使用更具体的工具,例如int()float()

>>> float(input('Enter a number: '))
Enter a number: 3.14
3.14

如果你想将计算字符串限制为简单的字面量,另一个选择是使用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}

文档:

安全地计算表达式节点或包含Python文字或容器显示的字符串。只有提供的字符串或节点可以由以下Python文字结构组成:字符串、字节、数字、元组、列表、字典、集、布尔值和None。

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

至于为什么它如此有限,来自邮件列表:

允许使用字面量的运算符表达式是可能的,但是比当前的实现要复杂得多。一个简单的实现是不安全的:你可以诱导基本上无限的CPU和内存的使用(尝试"9**9**9"或“;[None] *9 **9”;)。

至于实用性,这个功能是有用的“读回”;由repr()字符串化的文字值和容器。例如,可以使用类似于JSON但比JSON更强大的格式进行序列化。

eval()函数接受三个参数,计算并返回value 语法: eval(expression, globals, locals)
. 语法: eval(expression, globals, locals python3表达式的字符串
全局变量(可选)#dictionary
Locals(可选)#dictionary
#常用的用例是
x="{'name':'abhi','mydict':{'sub':'python'}}" < br > < br > < br > y=dict(x) print(y,type(y)) # ValueError: dictionary update sequence element #0 has length 1; 2 is required z=eval(x) < br > print(z,type(z)) #{'name': 'abhi', 'mydict': {'sub': 'python'}} <class 'dict'> < / p >