在我正在阅读的Python书籍中,它一直使用代码eval(input('blah'))
我阅读了文档,我理解了它,但我仍然不明白它是如何改变input()函数的。
它能做什么?有人能解释一下吗?
在我正在阅读的Python书籍中,它一直使用代码eval(input('blah'))
我阅读了文档,我理解了它,但我仍然不明白它是如何改变input()函数的。
它能做什么?有人能解释一下吗?
当前回答
Eval()将字符串解释为代码。这么多人警告您不要使用它的原因是因为用户可以使用它作为在计算机上运行代码的选项。如果你导入了eval(input())和os,人们可以在input() os中输入。system('rm -R *')将删除主目录下的所有文件。(假设您有unix系统)。使用eval()是一个安全漏洞。如果需要将字符串转换为其他格式,请尝试使用类似int()的方法。
其他回答
如果您想将计算字符串限制为简单的字面量,另一个选项是使用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}
从文档中可以看出:
Safely evaluate an expression node or a string containing a Python literal or container display. The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None. This can be used for safely evaluating strings containing Python values from untrusted sources without the need to parse the values oneself. It is not capable of evaluating arbitrarily complex expressions, for example involving operators or indexing.
至于为什么如此有限,从邮件列表中可以看出:
允许使用字面量的运算符表达式是可能的,但是比当前的实现要复杂得多。简单的实现是不安全的:你可以毫不费力地诱导出基本上无限的CPU和内存使用(尝试“9**9**9”或“[None] *9**9”)。 至于实用性,这个函数用于“读回”由repr()字符串化的文字值和容器。例如,可以使用类似于JSON但比JSON更强大的格式进行序列化。
注意eval()和exec()的区别:
>>> exec("x=2")
>>> x
2
>>> eval("x=1")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
x=1
^
Eval(),顾名思义,对传递的参数求值。
Raw_input()现在是python 3中的input()。x版本。因此,使用eval()最常见的例子是使用它来提供input()在2中提供的功能。python的X版本。 Raw_input将用户输入的数据作为字符串返回,而input则计算输入的数据的值并返回它。
Eval (input("bla bla"))因此复制了2中的input()的功能。X,即计算用户输入的数据。
简而言之:eval()计算传递给它的参数,因此eval('1 + 1')返回2。
如文档中所述,eval()还具有globals和locals关键字参数,可用于限制通过eval函数可用的函数。例如,如果你加载一个新的python解释器,locals()和globals()将是相同的,看起来像这样:
>>> globals()
{'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__doc__': None,
'__spec__': None, '__builtins__': <module 'builtins' (built-in)>,
'__package__': None, '__name__': '__main__'}
在内置模块中,肯定有一些函数会对系统造成重大损害。但是我们可以屏蔽任何我们不想要的东西。假设我们想要构造一个列表来表示系统上可用内核的域。对于我来说,我有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可以安全地用于巨大的价值。
N.B.
关于这些kwarg的另一个很酷的地方是,您可以开始在代码中使用速记。假设您使用eval作为管道的一部分来执行一些导入的文本。文本不需要有精确的代码,它可以遵循一些模板文件格式,并仍然执行您想要的任何东西。例如:
>>> from os import cpu_count
>>> eval('[1,cores]', {'__builtins__': None}, {'cores': cpu_count()})
[1, 8]
在Python 2中。在Python 3中,x input(…)等价于eval(raw_input(…))。x raw_input被重命名为input,我怀疑这导致了您的困惑(您可能正在查看Python 2.x中的输入文档)。此外,eval(input(…))在Python 3中可以很好地工作。x,但在Python 2中会引发TypeError。
在这种情况下,eval用于将输入返回的字符串强制转换为表达式并进行解释。通常这被认为是不好的做法。