📜  Python eval()

📅  最后修改于: 2020-09-20 04:00:58             🧑  作者: Mango

eval()方法解析传递给该方法的表达式,并在程序中运行Python表达式(代码)。

简而言之, eval() 函数在程序内运行Python代码(作为参数传递)。

eval()的语法为:

eval(expression, globals=None, locals=None)

eval()参数

eval() 函数采用三个参数:

  1. expression-解析并评估为Python表达式的字符串
  2. 全局变量(可选)-字典
  3. locals(可选)-映射对象。字典是Python常用的标准映射类型。

globalslocals globals的使用将在本文后面讨论。

从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() 。您可以通过将可选的globalslocals参数(字典)传递给eval() 函数。

1.当省略globals和locals参数时

如果两个参数都被省略(如前面的示例所示),则在当前范围内执行该expression 。您可以使用以下代码检查可用的变量和方法:

print(eval('dir()')

2.传递全局参数;省略locals参数

globalslocals参数(字典),分别用于全局和局部变量。如果省略了locals字典,则默认为globals字典。这意味着, globals将用于全局变量和局部变量。

注意:您可以分别使用globals()和locals()内置方法在Python检查当前的全局字典和局部字典。

示例3:将空字典作为全局参数传递

from math import *
print(eval('dir()', {}))

# The code will raise an exception
print(eval('sqrt(25)', {}))

输出

['__builtins__']
Traceback (most recent call last):
  File "", line 5, in 
    print(eval('sqrt(25)', {}))
  File "", line 1, in 
NameError: name 'sqrt' is not defined

如果将空字典作为globals传递,则仅__builtins__可用于expression ( eval()第一个参数)。

即使我们已在上述程序中导入了math模块, expression无法访问该数学模块提供的任何函数。

示例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.通过全球和本地字典

您可以通过传递locals字典来使所需的函数和变量可用。例如:

from math import *

a = 169
print(eval('sqrt(a)', {'__builtins__': None}, {'a': a, 'sqrt': sqrt}))

输出

13.0

在此程序中, expression只能具有sqrt()方法和变量a 。所有其他方法和变量均不可用。

通过传递globalslocals字典来限制eval()的使用将使您的代码安全,尤其是在使用用户提供给eval()方法的输入时。

注意:有时,即使名称有限, eval()也不安全。使对象及其方法可访问后,几乎可以完成任何事情。唯一安全的方法是验证用户输入。