📅  最后修改于: 2020-04-10 01:12:22             🧑  作者: Mango
本文讨论了Python中的内置函数eval。
这是Python中的一个有趣的实用工具,它允许Python程序在其内部运行Python代码。
所述的eval()方法解析传递给它的Python表达式(代码)。
eval的语法为:
eval(expression, globals=None, locals=None)
让我们借助一个简单的Python程序进行探索:
from math import *
def secret_function():
return "密钥是1234"
def function_creator():
# 要评估的表达式
expr = raw_input("输入函数(以x表示):")
# 表达式中使用的变量
x = int(raw_input("输入x的值:"))
# 评价表达
y = eval(expr)
# 打印评估结果
print("y = {}".format(y))
if __name__ == "__main__":
function_creator()
function_creator是评估用户创建的数学函数的函数。
考虑一个输出:
输入函数(以x表示):x*(x+1)*(x+2)
输入x的值:3
y = 60
让我们分析一下代码:
评估漏洞
我们当前的function_creator版本具有一些漏洞。
用户可以轻松地在程序中公开隐藏的值,也可以调用危险函数,因为eval将执行传递给它的任何内容。
例如,如果您这样输入:
输入函数(以x表示):secret_function()
输入x的值:0
您将获得输出:
y = 密钥是1234
另外,考虑在Python程序中导入os模块时的情况。os模块提供了使用操作系统功能的便携式方法,例如:读取或写入文件。单个命令可以删除系统中的所有文件!
当然,在大多数情况下(例如桌面程序),用户不能做超过编写自己的Python脚本的操作,但是在某些应用程序(例如Web应用程序,信息亭计算机)中,这可能会带来风险!
解决方案是将eval限制仅为我们要提供的函数和变量。
使eval安全
eval函数具有显式传递可以访问的函数或变量列表的功能。我们需要以字典的形式将其作为参数传递。
考虑下面的示例:
from math import *
def secret_function():
return "密钥是1234"
def function_creator():
# 要评估的表达式
expr = raw_input("输入函数(以x表示):")
# 表达式中使用的变量
x = int(raw_input("输入x的值:"))
# 在安全字典中传递变量x
safe_dict['x'] = x
# 评价表达
y = eval(expr, {"__builtins__":None}, safe_dict)
# 打印评估结果
print("y = {}".format(y))
if __name__ == "__main__":
# list of safe methods
safe_list = ['acos', 'asin', 'atan', 'atan2', 'ceil', 'cos',
'cosh', 'degrees', 'e', 'exp', 'fabs', 'floor',
'fmod', 'frexp', 'hypot', 'ldexp', 'log', 'log10',
'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt',
'tan', 'tanh']
# 创建安全方法字典
safe_dict = dict([(k, locals().get(k, None)) for k in safe_list])
function_creator()
现在,如果我们尝试运行以上程序,例如:
输入函数(以x表示:secret_function()
输入x的值:0
我们得到输出:
NameError: name 'secret_function' is not defined
让我们逐步分析以上代码:
safe_dict = dict([(k, locals().get(k, None)) for k in safe_list])
locals()是一个Python内置方法,该方法返回一个字典,该字典将本地范围内的所有方法和变量与其名称空间进行映射。
safe_dict['x'] = x
y = eval(expr, {"__builtins__":None}, safe_dict)
因此,通过这种方式,我们使eval求值函数安全无虞!
eval的用途
如上文所述,由于安全原因,eval的使用率不高。
尽管如此,在某些情况下它还是很方便的: