eval和ast.literal_eval的区别

eval()

eval函数在Python中的作用就是做数据类型的转换,把数据还原成它本身或是能够转换成的数据类型,官方解释为:将字符串str当成有效的表达式来求值并返回计算结果

使用eval可以实现从元祖,列表,字典型的字符串到元祖,列表,字典的转换,

>>> a='[1,2,3]'
>>> b=eval(a)
>>> b
[1, 2, 3]

>>> type(a)

>>> type(b)


>>> c="{1:'a',2:'b'}"
>>> d=eval(c)
>>> d
{1: 'a', 2: 'b'}
>>> print(type(c),type(d))
 

eval不仅可以转换数据类型,还可以直接计算出结果,例如:

>>> e='1+1'
>>> f=eval(e)
>>> f
2

所以eval强大的背后,也存在着巨大的隐患,例如,用户恶意输入一下字符串:

>>> eval("os.system('whoami')")
desktop-odh0osg\xx
0
>>>

open(r'D://filename.txt', 'r').read()
__import__('os').system('dir')
__import__('os').system('rm -rf /etc/*')

那么eval就会执行这些命令,显示你电脑目录结构,读取文件,删除文件…如果是格盘等更严重的操作,也会执行,在实际开发中,就会出现很严重的事故!

ast.literal_eval()

这里就可以使用ast.literal_eval,安全的处理问题,

简单点说ast模块就是帮助Python应用来处理抽象的语法解析的。而该模块下的literal_eval()函数:则会判断需要计算的内容计算后是不是合法的python类型,如果是则进行运算,否则就不进行运算。

比如说上面的计算操作,及危险操作,如果换成了ast.literal_eval(),都会拒绝执行。报值错误,不合法的字符串!

官方给出的解释:

ast.``literal_eval(node_or_string)

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

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

>>> import ast
>>> ast.literal_eval('1+1')
Traceback (most recent call last):
  File "", line 1, in 
  File "c:\users\xx\anaconda3\Lib\ast.py", line 91, in literal_eval
    return _convert(node_or_string)
  File "c:\users\xx\anaconda3\Lib\ast.py", line 90, in _convert
    return _convert_signed_num(node)
  File "c:\users\xx\anaconda3\Lib\ast.py", line 63, in _convert_signed_num
    return _convert_num(node)
  File "c:\users\xx\anaconda3\Lib\ast.py", line 55, in _convert_num
    raise ValueError('malformed node or string: ' + repr(node))
ValueError: malformed node or string: <_ast.BinOp object at 0x0000029751A13390>
>>>

>>> ast.literal_eval('[1,2,3]')
[1, 2, 3]
>>> ast.literal_eval('(1,2.3,4)')
(1, 2.3, 4)
>>>

在实际开发中,为了避免不必要的麻烦,可以使用ast.literal_eval(),来获取原来的数据类型,

你可能感兴趣的:(eval和ast.literal_eval的区别)