Python的eval()做什么?

Bil*_*ljk 280 python eval

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

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

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

BYS*_*YS2 248

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

eval示例(交互式shell):

>>> x = 1
>>> eval('x + 1')
2
>>> eval('x')
1
Run Code Online (Sandbox Code Playgroud)

  • 在你发现需要它之前它似乎没用.它在codepad.org等网站上使用,允许您在测试环境中执行脚本.`eval()`也可用于执行高动态代码,但在使用之前,您应该充分了解安全性和性能风险. (59认同)
  • 哈哈,这是一个简单的例子,但你可以让用户键入一个任意命令并让python执行它.因此,您可以让用户键入命令字符串,然后让python将其作为代码运行.例如:eval("__ import __('os').remove('file')"). (24认同)
  • @GeorgeCummins:codepag.org在沙箱中运行所有内容:一个带有ptrace的chroot jail在虚拟机中检查,以防止恶意代码做任何坏事.比简单的评估要复杂得多.此外,eval是特定于Python的.codepad支持一堆语言. (14认同)
  • @GeorgeCummins,codepad.org不使用`eval`,也不能用`eval`做它. (6认同)
  • @GeorgeCummins,codepad运行一个非常复杂的系统来安全地运行任意程序.`eval`,除了不安全之外,不能运行像codepad这样的整个程序,因为它只能评估单个表达式. (3认同)

Cof*_*ain 150

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

  • @Rohmer,不安全的数据可以来自任何地方:Web请求,表单输入字段,文件读取......不仅仅来自控制台输入.即使您自己编写文件,它仍然可以包含最初来自不受信任来源的输入.因此,在许多情况下,"eval"是一个安全问题. (17认同)
  • 你的意思是使用`eval`和`input()`是一个安全漏洞.不要将`input()`放在eval语句中,你会没事的. (14认同)
  • 由于`input`通常从控制台获取其数据,因此用户可以直接退出程序并键入`rm -R *`... (2认同)

Grr*_*Grr 51

这里有很多好的答案,但没有一个描述在eval()globalslocalskwargs 的上下文中的使用,即eval(expression, globals=None, locals=None)(参见eval 这里的文档).

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

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

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

>>>from os import cpu_count
>>>eval('[1, cpu_count()]')
[1, 8]
Run Code Online (Sandbox Code Playgroud)

同样所有__builtins__都可用.

>>>eval('abs(-1)')
1
Run Code Online (Sandbox Code Playgroud)

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

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

我们已经有效地阻止了所有__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
Run Code Online (Sandbox Code Playgroud)

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

NB

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

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

  • 这不能作为监狱。你可以获得内置函数,但仍然运行危险的代码,如下所示(运行 `rm -rf *`): `eval("[a for a in ().__class__.__bases__[0].__subclasses__() if 'catch_warnings' in a.__name__][0]()._module.__builtins__['__import__']('os').system('rm -rf *')", {"__builtins__": None})`。 (2认同)

zee*_*kay 29

在Python 2.x input(...)中相当于eval(raw_input(...)),在Python 3.x raw_input中重命名input,我怀疑这会引起你的困惑(你可能正在查看inputPython 2.x 中的文档).另外,eval(input(...))在Python 3.x中可以正常工作,但会TypeError在Python 2中提升.

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


Mar*_*hen 6

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

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

了解更多关于EVAL 这里.


小智 5

也许是读一行并解释它的一个令人误解的例子。

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


Nik*_*ick 5

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

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

将其读取为变量并进行编辑:

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

输出:

{'Greeting': 'Hello world'}
Run Code Online (Sandbox Code Playgroud)

  • 这如何回答询问“ eval”的问题? (6认同)

Rub*_*bal 5

eval()顾名思义,评估传递的参数.

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

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

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


小智 5

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

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

>>> input('Enter a number: ')
Enter a number: 3
>>> '3'
>>> input('Enter a number: ')
Enter a number: 1+1
'1+1'
Run Code Online (Sandbox Code Playgroud)

因此,eval()将评估作为字符串的返回值(或表达式)并返回整数/浮点数。

>>> eval(input('Enter a number: '))
Enter a number: 1+1
2
>>> 
>>> eval(input('Enter a number: '))
Enter a number: 3.14
3.14
Run Code Online (Sandbox Code Playgroud)

当然,这是一种不好的做法。在这种情况下应该使用int()orfloat()代替eval()

>>> float(input('Enter a number: '))
Enter a number: 3.14
3.14
Run Code Online (Sandbox Code Playgroud)


Bri*_*rns 5

如果要将评估字符串限制为简单文字,另一种选择是使用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}
Run Code Online (Sandbox Code Playgroud)

文档

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

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

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

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

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