在Python中,我們有許多內置方法,這些方法對於使Python成為所有人的便捷語言至關重要,而eval是其中一種。eval函數的語法如下:
eval(expression, globals, locals)如上所示,eval函數採用三個參數:
expression –需要一個字符串,該字符串將被解析並評估為Python表達式globals(可選)–一個字典,用於指定可用的全局方法和變量。locals(可選)-另一個字典,用於指定可用的本地方法和變量。稍後將在本文中顯示對global(全局變量)s和locals(本地變量)的使用。eval在Python中做什麼?eval函數解析expression參數並將其評估為python表達式。換句話說,我們可以說這個函數解析了傳遞給它的表達式並在程序中運行python expression(code)。
為了評估基於字符串的表達式,Python的eval函數運行以下步驟:
解析表達式
編譯成字節碼
將其評估為Python表達式
返回評估結果
這意味著當我們將任何python表達式作為「字符串」傳遞給eval函數時,它會評估該表達式並將結果返回為整數或浮點數。以下是一些簡單的示例,它們將使您更加清楚。
這是在Python中使用eval將字符串轉換為整數,複數或浮點數的簡單方法:
<code> num =「 23」 float_num =「 53.332」 complex_num =「 2 + 3j」 str1 =「 Not number」 print(eval(num),type(eval(num)))print(eval(float_num),type( eval(float_num)))print(eval(complex_num),type(eval(complex_num)))print(eval(str1),type(eval(str1)))</ code>OUTPUT: 23 53.332 (2+3j) Traceback (most recent call last): File "main.py", line 8, in print(eval(str1),type(eval(str1))) File "", line 1 Not number ^ SyntaxError: unexpected EOF while parsing如您所見,eval函數能夠識別字符串中的表達式並將其轉換為相應的類型。但是,當我們僅傳遞字符和字母時,它返回了一個錯誤。這應該清楚eval的實際作用。
這裡有更多的例子,其中我們不僅僅涉及類型轉換,實際上我們看到了eval函數評估字符串中的表達式。
我們還可以使用eval求解數學表達式:
<code> expr =「(2+(3 * 2))/ 2」 print(eval(expr))</ code>我們甚至可以在字符串中使用變量名,Python還將對它們進行評估,如下所示<code>num=10expr="(2+(3*2))/2 + num"print(eval(expr))</code>我們還可以在字符串內部使用內置函數,如下所示:
<code>print(eval("sum([8, 16, 34])"))</code>為了更好地了解eval函數,讓我們看看如果將表達式用兩個字符串括起來,它將如何響應,如下所示:
<code>#string in another stringexpr="'2+3'"print(eval(expr))print(eval(eval(expr)))</code>因此,第一個eval函數只是返回字符串中的表達式,但是在另一個eval函數中使用eval時,我們得到了表達式的答案。
如何在python中使用eval ?在上一節中,我們已經了解了如何使用eval函數,但是在這裡,我們將了解eval函數的其他參數如何影響其工作。因此,Python中的eval 還有兩個參數,即viz-globals和locals。
全局變量是當前全局範圍或命名空間中可用的對象。您可以從代碼中的任何位置訪問它們。
在執行時,傳遞給字典中全局變量的所有對象將對eval()可用。請查看以下示例,該示例顯示了如何使用自定義詞典為eval函數提供全局名稱空間:
<code>num1 = 100 print(eval("num1 + 100", {"num1": num1}))num2 = 200 print(eval("num1 + num2", {"num1": num1,"num2": num2}))print(eval("num1 + num2", {"num1": num1}))</code>OUTPUT: 200 300 Traceback (most recent call last): File "main.py", line 5, in print(eval("num1 + num2", {"num1": num1})) File "", line 1, in NameError: name 'num2' is not defined如您在上面的示例中看到的,首先eval只能訪問num1和num2,但是當我從globals字典中刪除num2時,它拋出了一個錯誤,因為它現在無法識別num2。
但是,為什麼在我甚至沒有將值傳遞給globals參數的上述示例中都沒有發生這種錯誤?
事實證明,當您在不提供globals參數的情況下調用eval函數時,該函數將使用globals()函數返回的字典作為其全局命名空間來評估表達式。
因此,在上面的示例中,我們可以自由訪問所有變量,因為它們是當前全局範圍中包含的全局變量。
現在,如果將空字典傳遞給全局變量會發生什麼,讓我們看看:
<code>a=2print(eval("sum([2, 2, 2])", {}))print(eval("sum([a, 2, 2])", {}))</code>OUTPUT:6 Traceback (most recent call last): File "main.py", line 3, in print(eval("sum([a, 2, 2])", {})) File "", line 1, in NameError: name 'a' is not defined因此,eval函數可以成功識別函數和,但無法識別對象「 a」,因此返回錯誤。
當我們向全局變量提供自定義詞典時,它包含鍵「 __builtins__」的值,但如果不包含該值,則在解析表達式之前,將自動在「 __builtins__」下插入對內置字典的引用。這樣可以確保eval()函數在評估表達式時將完全訪問所有Python的內置名稱。這說明了在上面的示例中,如何通過eval識別函數和。
現在讓我們看看什麼是局部變量以及它們如何擴展eval函數的功能。與全局變量不同,局部對象在函數內部聲明,不能在函數外部訪問。
類似地,locals參數採用一個字典,在字典中我們添加了一些對象,而eval()函數將這些對象視為本地對象。請看下面的例子:
<code>print(eval("sum([a, 2, 2])",{}, {"a":2}))print(a)</code>OUTPUT: 6 Traceback (most recent call last): File "main.py", line 2, in print(a) NameError: name 'a' is not defined請注意,要向本地人提供字典,您首先需要向全局人提供字典。不能將關鍵字參數與eval()一起使用
這似乎令人困惑,但是在下面的示例中,我同時使用了globals和locals參數,您將看到它們如何影響結果。
<code>print(eval("abs(-1)"))#By keeping __builtins__":None,eval will recognise no in-buiilt functionprint(eval('abs(-1)',{"__builtins__":None}))</code>OUTPUT:1Traceback (most recent call last): File "main.py", line 1, in print(eval('abs(-1)',{"__builtins__":None})) File "", line 1, in TypeError: 'NoneType' object is not subscriptable現在,我們希望該函數在eval函數中起作用,因此將其添加到本地字典中。現在,eval函數可以識別abs函數,而不能識別任何其他函數。
<code>print(eval('abs(-1)',{"__builtins__":None},{"abs":abs}))</code>全局變量和局部變量之間的主要實際區別是,如果該密鑰尚不存在,Python會自動將「 __builtins__」鍵插入全局變量。無論是否為全局變量提供自定義詞典,都會發生這種情況。另一方面,如果向本地人提供自定義詞典,則在執行eval函數期間該詞典將保持不變。
評估的局限性Python中的eval()很有用,但也有重要的安全隱患。eval函數被認為是不安全的,因為它允許您或其他用戶動態執行任意Python代碼。那對我們有什麼影響?
假設您正在伺服器上運行的應用程式中要求用戶輸入。現在,如果您在輸入上使用eval函數,則用戶可以訪問伺服器本身。用戶可以像這樣傳遞一些可疑的代碼:
<code> __ import __('subprocess')。getoutput('rm –rf *')</ code>上面的代碼將刪除應用程式當前目錄中的所有文件,這肯定會影響我們。
因此,最好避免使用eval函數,但是如果仍然要使用eval函數,我們可以藉助globals和locals參數來限制其功能。正如我們在上一節中看到的那樣,我們限制eval函數,使其只能使用python的abs函數。
例如,假設我有一個應用程式,可以在給定數字或所有給定數字的總和中找到最小值。像這樣使用eval的最方便方法
<code> print(eval(input()))但是,這是一種不好的編程方式。我們無法控制用戶的輸入內容,因此我們可以利用globals和locals參數,使得eval不能識別sum()和min()以外的函數。這肯定會和上面的代碼做同樣的事情,但是要安全得多。
<code> print(eval(input(),{「 __ builtins __」:None},{「 min」:min,「 sum」:sum}))</ code>
希望大家可以通過本文了解到Python中的 eval函數,如果您想了解更多有關python案例實操,建議下載閱讀「Python經典80案例實操」
點個再看,證明你還愛我