eval()
方法解析传递给此方法的表达式,并在程序中运行 Python 表达式(代码)。
示例
number = 9
# eval performs the multiplication passed as argument
square_number = eval('number * number')
print(square_number)
# Output: 81
eval() 语法
eval()
的语法是
eval(expression, globals=None, locals=None)
eval() 参数
eval()
函数接受三个参数
关于 globals 和 locals 的使用将在本文后面讨论。
eval() 返回值
eval()
方法返回从 expression 求值得到的结果。
示例 1:eval() 在 Python 中如何工作
x = 1
print(eval('x + 1'))
输出
2
这里,eval()
函数对表达式 x + 1
求值,并使用 print() 来显示这个值。
示例 2:演示 eval() 用法的实际示例
# Perimeter of Square
def calculatePerimeter(l):
return 4*l
# Area of Square
def calculateArea(l):
return l*l
expression = input("Type a function: ")
for l in range(1, 5):
if (expression == 'calculatePerimeter(l)'):
print("If length is ", l, ", Perimeter = ", eval(expression))
elif (expression == 'calculateArea(l)'):
print("If length is ", l, ", Area = ", eval(expression))
else:
print('Wrong Function')
break
输出
Type a function: calculateArea(l) If length is 1 , Area = 1 If length is 2 , Area = 4 If length is 3 , Area = 9 If length is 4 , Area = 16
使用 eval() 时的警告
考虑一种情况,您正在使用 Unix 系统(macOS, Linux 等)并且已经导入了 os
模块。os 模块提供了一种可移植的方式来使用操作系统功能,如读写文件。
如果您允许用户使用 eval(input())
输入一个值,用户可能会发出命令来更改文件,甚至使用命令 os.system('rm -rf *')
删除所有文件。
如果您在代码中使用 eval(input())
,最好检查一下用户可以使用哪些变量和方法。您可以使用 dir() 方法查看哪些变量和方法是可用的。
from math import *
print(eval('dir()'))
输出
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'os', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']
限制在 eval() 中可用方法和变量的使用
通常情况下,expression(eval()
的第一个参数)中使用的所有可用方法和变量可能并非都是必需的,甚至可能存在安全漏洞。您可能需要限制 eval()
对这些方法和变量的使用。您可以通过向 eval()
函数传递可选的 globals 和 locals 参数(字典)来实现这一点。
1. 当 globals 和 locals 参数都省略时
如果两个参数都省略(如我们前面的示例),expression 将在当前作用域中执行。您可以使用以下代码检查可用的变量和方法
print(eval('dir()')
2. 传递 globals 参数;省略 locals 参数
globals 和 locals 参数(字典)分别用于全局和局部变量。如果省略 locals 字典,它将默认为 globals 字典。这意味着,globals 将同时用于全局和局部变量。
注意: 您可以使用内置方法 globals() 和 locals() 分别检查 Python 中当前的全局和局部字典。
示例 3:传递空字典作为 globals 参数
from math import *
print(eval('dir()', {}))
# The code will raise an exception
print(eval('sqrt(25)', {}))
输出
['__builtins__'] Traceback (most recent call last): File "<string>", line 5, in <module> print(eval('sqrt(25)', {})) File "<string>", line 1, in <module> NameError: name 'sqrt' is not defined
如果您传递一个空字典作为 globals,那么只有 __builtins__
对 expression
(eval()
的第一个参数)可用。
尽管我们在上面的程序中导入了 math
模块,但 expression 无法访问 math 模块提供的任何函数。
示例 4:使某些方法可用
from math import *
print(eval('dir()', {'sqrt': sqrt, 'pow': pow}))
输出
['__builtins__', 'pow', 'sqrt']
在这里,表达式只能使用 sqrt()
和 pow()
方法以及 __builtins__
。
也可以根据您的意愿更改 expression 可用的方法名称
from math import *
names = {'square_root': sqrt, 'power': pow}
print(eval('dir()', names))
# Using square_root in Expression
print(eval('square_root(9)', names))
输出
['__builtins__', 'power', 'square_root'] 3.0
在上面的程序中,square_root()
使用 sqrt()
计算平方根。然而,尝试直接使用 sqrt()
将会引发错误。
示例 5:限制内置函数的使用
您可以如下限制在 expression 中使用 __builtins__
eval(expression, {'__builtins__': None})
3. 同时传递 globals 和 locals 字典
您可以通过传递 locals 字典,使所需的函数和变量可用。例如
from math import *
a = 169
print(eval('sqrt(a)', {'__builtins__': None}, {'a': a, 'sqrt': sqrt}))
输出
13.0
在这个程序中,expression 只能拥有 sqrt()
方法和变量 a。所有其他方法和变量都不可用。
通过传递 globals 和 locals 字典来限制 eval()
的使用将使您的代码更加安全,特别是当您使用用户提供给 eval()
方法的输入时。
注意: 有时,即使名称有限,eval()
也不是安全的。当一个对象及其方法变得可访问时,几乎可以做任何事情。唯一安全的方法是验证用户输入。