eval()方法解析傳遞給該方法的表達式,并在程序中運行python表達式(代碼)。
簡而言之,eval()方法在程序內運行python代碼(作為參數傳遞)。
eval()的語法為:
eval(expression, globals=None, locals=None)
eval()具有三個參數:
expression-解析并評估為Python表達式的字符串
globals(可選)-字典
locals(可選)-映射對象。字典是Python中常用的標準映射類型。
稍后將在本文中討論全局變量(globals)和本地變量(locals)的使用。
eval()方法返回從expression求值的結果。
x = 1 print(eval('x + 1'))
運行該程序時,輸出為:
2
在這里,eval()計算表達式x + 1并打印出來。
# 正方形的周長 def calculatePerimeter(l): return 4*l # 面積的平方 def calculateArea(l): return l*1 property = input("輸入要使用的函數: ") for l in range(1, 5): if (property == 'calculatePerimeter(l)'): print("如果長度是 ", l , ", 周長 = ", eval(property)) elif (property == 'calculateArea(l)'): print("如果長度是 ", l , ", 面積 = ", eval(property)) else: print('錯誤的功能') break
上面程序的輸出將是:
輸入要使用的函數: calculatePerimeter(l) 如果長度是 1 , 周長 = 4 如果長度是 2 , 周長 = 8 如果長度是 3 , 周長 = 12 如果長度是 4 , 周長 = 16
考慮一種情況,您正在使用Unix系統(tǒng)(macOS,Linux等),并且已導入os模塊。os模塊提供了使用操作系統(tǒng)功能的便攜式方法,例如:讀取或寫入文件。
如果允許用戶使用來輸入值eval(input()),則用戶可以發(fā)出命令來更改文件,甚至可以使用command刪除所有文件os.system('rm -rf *')。
如果eval(input())在代碼中使用,最好檢查用戶可以使用哪些變量和方法。您可以使用dir()方法查看可用的變量和方法。
from math import * print(eval('dir()'))
當您運行該程序時,輸出將類似于:
['__annotations__', '__builtins__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'squareRoot', 'tan', 'tanh', 'tau', 'trunc']
通常,可能不需要使用表達式(eval()的第一個參數)中使用的所有可用方法和變量,甚至可能有安全漏洞。您可能需要限制將這些方法和變量用于eval()。您可以通過將可選的globals和locals參數(字典)傳遞給eval()方法來實現。
如果兩個參數都被省略(如前面的示例所示),則在當前范圍內執(zhí)行該表達式。您可以使用以下代碼檢查可用的變量和方法:
print(eval('dir()'))
globals和locals參數(字典),分別用于全局和局部變量。如果省略了locals字典,則默認為globals字典。這意味著,globals將用于全局變量和局部變量。
注意:您可以分別使用globals()和locals()內置方法在Python中檢查當前的全局字典和局部字典。
from math import * print(eval('dir()', {})) # 下面的代碼將引發(fā)異常 # print(eval('sqrt(25)', {}))
如果將空字典作為globals傳遞,則僅__builtins__可用于表達式(expression)(eval()的第一個參數)。即使我們在上面的程序中導入了math模塊,表達式(expression)也無法訪問math模塊提供的任何功能。
運行該程序時,輸出為:
['__builtins__']
from math import * print(eval('dir()', {'sqrt': sqrt, 'pow': pow}))
在此,表達式還可以使用sqrt()和pow()方法以及__builtins__。
另外,可以根據您的意愿更改可用于表達式(expression)的方法的名稱。
from math import * print(eval('dir()', {'squareRoot': sqrt, 'pow': pow})) # 在表達式中使用平方根 print(eval('squareRoot(9)', {'squareRoot': sqrt, 'pow': pow}))
在上述程序中,squareRoot()計算平方根(類似的功能,如sqrt())。但是,嘗試使用sqrt()將引發(fā)錯誤。
您可以按以下方式限制__builtins__在表達式(expression)中的使用:
eval(expression, {'__builtins__': None})
您可以通過傳遞本地(locals)字典來使所需的函數和變量可用。例如:
from math import * a = 5 print(eval('sqrt(a)', {'__builtins__': None}, {'a': a, 'sqrt': sqrt}))
運行該程序時,輸出為:
2.23606797749979
在此程序中,表達式(expression)(eval的第一個參數)只能具有sqrt()方法和變量a。所有其他方法和變量均不可用。
通過傳遞globals和locals字典來限制eval()的使用將使您的代碼安全,尤其是在使用用戶提供給eval()方法的輸入時。