一、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 函数。