在我正在阅读Python的书中,它继续使用代码eval(input('blah'))
我阅读了文档,我理解它,但我仍然没有看到它如何更改input()
函数。
它做什么?有人可以解释一下吗?
答案 0 :(得分:227)
eval函数允许Python程序在其自身内部运行Python代码。
eval示例(交互式shell):
>>> x = 1
>>> eval('x + 1')
2
>>> eval('x')
1
答案 1 :(得分:138)
eval()
将字符串解释为代码。这么多人警告你使用它的原因是因为用户可以使用它作为在计算机上运行代码的选项。如果您导入eval(input())
和os
,则可以输入input()
os.system('rm -R *')
,这将删除您主目录中的所有文件。 (假设你有一个unix系统)。使用eval()
是一个安全漏洞。如果您需要将字符串转换为其他格式,请尝试使用这些内容,例如int()
。
答案 2 :(得分:37)
这里有很多好的答案,但没有一个描述在eval()
和globals
kwargs的上下文中使用locals
,即eval(expression, globals=None, locals=None)
(请参阅{{1}的文档1}} here)。
这些可用于限制通过eval
方法可用的方法。例如,如果你加载一个新的python解释器,eval
和locals()
将是相同的,看起来像这样:
globals()
>>> globals()
{'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__doc__': None,
'__spec__': None, '__builtins__': <module 'builtins' (built-in)>,
'__package__': None, '__name__': '__main__'}
模块中肯定有一些方法可以对系统造成重大损害。但是有可能阻止任何我们不想要的东西。我们来举个例子吧。假设我们要构建一个列表来表示系统上可用核心的域。对我来说,我有8个内核,所以我想要一个列表builtins
。
[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__
现在我们有cpu_count方法可用,同时仍然阻止我们不想要的一切。在我看来,这是超级强大的,显然从其他答案的范围不是一个常见的实现。对于这样的事情有很多用途,只要处理得当,我个人认为>>>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
可以安全地使用它。
N.B。
对于这些eval
而言,其他一些很酷的事情是你可以开始使用速记来代码。假设您使用eval作为管道的一部分来执行某些导入的文本。文本不需要具有确切的代码,它可以遵循一些模板文件格式,并且仍然执行您想要的任何内容。例如:
kwargs
答案 3 :(得分: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
返回的字符串强制转换为表达式并进行解释。通常这被认为是不好的做法。
答案 4 :(得分:6)
eval()
将传递的字符串作为Python表达式计算并返回结果。例如,eval("1 + 1")
解释并执行表达式"1 + 1"
并返回结果(2)。
您可能会感到困惑的一个原因是,您引用的代码涉及一定程度的间接性。首先执行内部函数调用(输入),以便用户看到“blah”提示符。让我们假设它们以“1 + 1”响应(为了清楚起见添加了引号,在运行程序时不输入它们),输入函数返回该字符串,然后将其传递给外部函数(eval),该函数解释字符串和返回结果(2)。
详细了解eval here。
答案 5 :(得分:5)
可能是一个误导性的例子,即阅读一行并解释它。
尝试eval(input())
并输入"1+1"
- 这应该打印2
。 Eval评估表达式。
答案 6 :(得分: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'}
答案 7 :(得分:5)
eval()
,顾名思义,评估传递的参数。
raw_input()
现在是input()
。因此,最常见的使用eval()
的示例是它用于提供input()
在2.x版本的python中提供的功能。
raw_input将用户输入的数据作为字符串返回,而input输入评估输入的数据的值并将其返回。
eval(input("bla bla"))
复制2.x中input()
的功能,即评估用户输入的数据。
简而言之:eval()
评估传递给它的参数,因此eval('1 + 1')
返回2。
答案 8 :(得分: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
答案 9 :(得分: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文字结构组成:字符串,字节,数字,元组,列表,字典,集合,布尔值和无。
这可用于安全地评估包含来自不受信任来源的Python值的字符串,而无需自己解析值。 不能能够评估任意复杂的表达式,例如涉及运算符或索引。
从the mailing list开始,为什么如此受限制:
允许使用带文字的运算符表达式,但是比当前实现复杂得多。一个简单的实现并不安全:您可以毫不费力地诱导CPU和内存的使用不受限制(尝试“ 9 ** 9 ** 9”或“ [无] * 9 ** 9”)。
至于有用性,此函数对于“读回”由repr()字符串化的文字值和容器很有用。例如,它可以用于序列化,其格式类似于JSON,但功能比JSON更强大。