Bootstrap

eval 和 ast.literal_eval 区别

一、eval函数

eval()官方文档里面给出来的功能解释是:将字符串string对象转化为有效的表达式参与求值运算返回计算结果。

eval(expression[, globals[, locals]])

参数

  • expression -- 表达式。
  • globals -- 变量作用域,全局命名空间,如果被提供,则必须是一个字典对象。
  • locals -- 变量作用域,局部命名空间,如果被提供,可以是任何映射对象。

 

运用比较多的功能是以下两种:

1、eval 作为 python 的一个内置函数,用于返回传入的字符串表达式结果。

print(eval('8+10'))
# 18

x=4;y=9
print(eval('x*y'))
# 36

print(eval('2+6==8'))
# True

存在 globals 变量作用域时,取 globals 中变量。

x=2;y=4;z=6
g = {'x':10,'y':20}
print(eval('x*y',g))
# 200

存在 locals 变量作用域时,取 locals 中变量。

x=2;y=4;z=6
g = {'x':10,'y':20}
l = {'y':30,'z':40}
print(eval('x*y',g,l))
# 300

 

2、将字符串转成字典、元祖、列表。

x = "{'a':10,'b':20,'c':30}"
print(eval(x))
# {'a': 10, 'b': 20, 'c': 30}

y = "[5,10,15]"
print(eval(y))
# [5, 10, 15]

z = "(1,2,3)"
print(eval(z))
# (1, 2, 3)

 

虽然 eval 处理字符串的能力很强,但也存在着非常大的安全隐患,因为它具有可以将字符串转成表达式执行的特性,所以它也就可以去执行系统命令。这样很容易被别有用心的人用来执行系统命令,删除关键文件系统,比如用户恶意输入就会获得当前目录文件。 

# 获取系统文件
eval("__import__('os').system('dir')")

 

二、ast.literal_eval 函数

ast 模块的 literal_eval 函数是对 python 内置函数 eval 存在安全隐患的一种安全解决方式。它会判断需要计算的内容是不是合法的Python类型,如果是则执行,否则就报错。例如使用 ast.literal_eaval 处理字符串转换

import ast

x = "{'a':10,'b':20,'c':30}"
print(ast.literal_eval(x))
# {'a': 10, 'b': 20, 'c': 30}

y = "[5,10,15]"
print(ast.literal_eval(y))
# [5, 10, 15]

z = "(1,2,3)"
print(ast.literal_eval(z))
# (1, 2, 3)

 

ast.literal_eval 不能执行上述 eval 函数的计算操作

import ast
ast.literal_eval('2+6')

'''
Traceback (most recent call last):
  File "d:\program files\python37\Lib\code.py", line 90, in runcode
    exec(code, self.locals)
  File "<input>", line 1, in <module>
  File "d:\program files\python37\Lib\ast.py", line 91, in literal_eval
    return _convert(node_or_string)
  File "d:\program files\python37\Lib\ast.py", line 90, in _convert
    return _convert_signed_num(node)
  File "d:\program files\python37\Lib\ast.py", line 63, in _convert_signed_num
    return _convert_num(node)
  File "d:\program files\python37\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 0x000001AC3D88FB70>
'''

 

当然也不会执行获取、删除文件系统等危险操作:

ast.literal_eval("__import__('os').system('dir')")

'''
Traceback (most recent call last):
  File "d:\program files\python37\Lib\code.py", line 90, in runcode
    exec(code, self.locals)
  File "<input>", line 2, in <module>
  File "d:\program files\python37\Lib\ast.py", line 91, in literal_eval
    return _convert(node_or_string)
  File "d:\program files\python37\Lib\ast.py", line 90, in _convert
    return _convert_signed_num(node)
  File "d:\program files\python37\Lib\ast.py", line 63, in _convert_signed_num
    return _convert_num(node)
  File "d:\program files\python37\Lib\ast.py", line 55, in _convert_num
    raise ValueError('malformed node or string: ' + repr(node))
ValueError: malformed node or string: <_ast.Call object at 0x000001AC3D89B940>
'''

 

 总结:当处理字符串转换时,虽然 eval 函数可以通过变量作用域限制一些危险操作,但无法完全堵住所有非法操作。所以我们使用安全性更高的 ast.literal_eval 替代 eval 函数。

 

;