天天看點

eval() python_如何在Python中使用eval ?

eval() python_如何在Python中使用eval ?

Python中的 eval是什麼?

在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>
           
OUTPUT:
4.0
           

我們甚至可以在字元串中使用變量名,Python還将對它們進行評估,如下所示

<code>num=10
expr="(2+(3*2))/2 + num"
print(eval(expr))</code>
           
OUTPUT:
14.0
           

我們還可以在字元串内部使用内置函數,如下所示:

<code>print(eval("sum([8, 16, 34])"))</code>
           
OUTPUT:
58
           

為了更好地了解eval函數,讓我們看看如果将表達式用兩個字元串括起來,它将如何響應,如下所示:

<code>#string in another string
expr="'2+3'"
print(eval(expr))
print(eval(eval(expr)))</code>
           
OUTPUT:
2+3                                                                                                                           
5
           

是以,第一個eval函數隻是傳回字元串中的表達式,但是在另一個eval函數中使用eval時,我們得到了表達式的答案。

如何在python中使用eval ?

在上一節中,我們已經了解了如何使用eval函數,但是在這裡,我們将了解eval函數的其他參數如何影響其工作。是以,Python中的eval 還有兩個參數,即viz-globals和locals。

全局變量是目前全局範圍或命名空間中可用的對象。您可以從代碼中的任何位置通路它們。

在執行時,傳遞給字典中全局變量的所有對象将對eval()可用。請檢視以下示例,該示例顯示了如何使用自定義詞典為eval函數提供全局名稱空間:

<code>num1 = 100  # A global variable
print(eval("num1 + 100", {"num1": num1}))
num2 = 200  # Another global variable
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=2
print(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 function
print(eval('abs(-1)',{"__builtins__":None}))</code>
           
OUTPUT:
1
Traceback (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>
           
OUTPUT:
1
           

全局變量和局部變量之間的主要實際差別是,如果該密鑰尚不存在,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()))
#input:sum([1,3,4])
#output:8 
#input:min([1,3,4])
#output:1 </ code>
           

但是,這是一種不好的程式設計方式。我們無法控制使用者的輸入内容,是以我們可以利用globals和locals參數,使得eval不能識别sum()和min()以外的函數。這肯定會和上面的代碼做同樣的事情,但是要安全得多。

<code> print(eval(input(),{“ __ builtins __”:None},{“ min”:min,“ sum”:sum}))</ code>
           
希望大家可以通過本文了解到Python中的 eval函數,如果您想了解更多有關python案例實操,建議閱讀“

Python經典80案例實操

繼續閱讀