Python中的求值函数 eval
本文讨论了Python中的内置函数eval。
这是Python中的一个有趣的实用工具,它允许Python程序在其内部运行Python代码。
所述的eval()方法解析传递给它的Python表达式(代码)。
eval的语法为:
eval(expression, globals=None, locals=None)
- expression表达式:此字符串被解析并作为Python表达式求值
- globals(可选):用于指定可用全局方法和变量的字典。
- locals(可选):另一个字典,用于指定可用的本地方法和变量。
让我们借助一个简单的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
让我们分析一下代码:
- 上面的函数将变量x中的任何表达式作为输入。
- 然后,用户必须输入x的值。
- 最后,我们通过传递expr作为参数,使用eval()内置函数评估Python表达式。
评估漏洞
我们当前的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_list。
- 接下来,我们创建一个安全方法字典。在此字典中,键是方法名称,值是它们的本地名称空间。
safe_dict = dict([(k, locals().get(k, None)) for k in safe_list])
locals()是一个Python内置方法,该方法返回一个字典,该字典将本地范围内的所有方法和变量与其名称空间进行映射。
safe_dict['x'] = x
- 在这里,我们也将局部变量x添加到safe_dict。eval函数不会识别x以外的任何局部变量。
- EVAL接受的词典本地以及全球变量作为自变量。因此,为了确保没有任何内置方法可用于eval表达式,我们还传递了另一个字典以及safe_dict,如下所示:
y = eval(expr, {"__builtins__":None}, safe_dict)
因此,通过这种方式,我们使eval求值函数安全无虞!
eval的用途
如上文所述,由于安全原因,eval的使用率不高。
尽管如此,在某些情况下它还是很方便的:
- 您可能希望使用它来允许用户输入自己的“脚本”:小表达式(甚至小函数),可用于自定义复杂系统的行为。
- eval有时还用于需要评估数学表达式的应用程序中。这比编写表达式解析器容易得多。
总计 0 评论