Python中eval與exec的使用及區別

pythontab發表於2018-10-19

最近開發中用到了eval()與exec()這兩個函式,不知道在哪種場景下用哪個函式,所以就翻了下Python的文件。這裡就來簡單說一下這兩個函式的區別

1. eval函式

函式的作用:


計算指定表示式的值。也就是說它要執行的Python程式碼只能是單個運算表示式(注意eval不支援任意形式的賦值操作),而不能是複雜的程式碼邏輯,這一點和lambda表示式比較相似。


函式定義:

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

引數說明:

expression:必選引數,可以是字串,也可以是一個任意的code物件例項(可以透過compile函式建立)。如果它是一個字串,它會被當作一個(使用globals和locals引數作為全域性和本地名稱空間的)Python表示式進行分析和解釋。

globals:可選引數,表示全域性名稱空間(存放全域性變數),如果被提供,則必須是一個字典物件。

locals:可選引數,表示當前區域性名稱空間(存放區域性變數),如果被提供,可以是任何對映物件。如果該引數被忽略,那麼它將會取與globals相同的值。

如果globals與locals都被忽略,那麼它們將取eval()函式被呼叫環境下的全域性名稱空間和區域性名稱空間。

返回值:

如果expression是一個code物件,且建立該code物件時,compile函式的mode引數是'exec',那麼eval()函式的返回值是None;

否則,如果expression是一個輸出語句,如print(),則eval()返回結果為None;

否則,expression表示式的結果就是eval()函式的返回值;

例項:

x = 10
def func():
  y = 20
  a = eval('x + y')
  print('a: ', a)
  b = eval('x + y', {'x': 1, 'y': 2})
  print('b: ', b)
  c = eval('x + y', {'x': 1, 'y': 2}, {'y': 3, 'z': 4})
  print('c: ', c)
  d = eval('print(x, y)')
  print('d: ', d)
func()


輸出結果:

a:  30
b:  3
c:  4
10 20
d:  None

對輸出結果的解釋:

對於變數a,eval函式的globals和locals引數都被忽略了,因此變數x和變數y都取得的是eval函式被呼叫環境下的作用域中的變數值,即:x = 10, y = 20,a = x + y = 30

對於變數b,eval函式只提供了globals引數而忽略了locals引數,因此locals會取globals引數的值,即:x = 1, y = 2,b = x + y = 3

對於變數c,eval函式的globals引數和locals都被提供了,那麼eval函式會先從全部作用域globals中找到變數x, 從區域性作用域locals中找到變數y,即:x = 1, y = 3, c = x + y = 4

對於變數d,因為print()函式不是一個計算表示式,沒有計算結果,因此返回值為None

2. exec函式

函式的作用:

動態執行Python程式碼。也就是說exec可以執行復雜的Python程式碼,而不像eval函式那麼樣只能計算一個表示式的值。

函式定義:

exec(object[, globals[, locals]])

引數說明:

object:必選引數,表示需要被指定的Python程式碼。它必須是字串或code物件。如果object是一個字串,該字串會先被解析為一組Python語句,然後在執行(除非發生語法錯誤)。如果object是一個code物件,那麼它只是被簡單的執行。

globals:可選引數,同eval函式

locals:可選引數,同eval函式

返回值:

exec函式的返回值永遠為None.

需要說明的是在Python 2中exec不是函式,而是一個內建語句(statement),但是Python 2中有一個execfile()函式。可以理解為Python 3把exec這個statement和execfile()函式的功能夠整合到一個新的exec()函式中去了。


eval()函式與exec()函式的區別

eval()函式只能計算單個表示式的值,而exec()函式可以動態執行程式碼段。

eval()函式可以有返回值,而exec()函式返回值永遠為None。

例項1:

我們把例項1中的eval函式換成exec函式試試:

x = 10
def func():
  y = 20
  a = exec('x + y')
  print('a: ', a)
  b = exec('x + y', {'x': 1, 'y': 2})
  print('b: ', b)
  c = exec('x + y', {'x': 1, 'y': 2}, {'y': 3, 'z': 4})
  print('c: ', c)
  d = exec('print(x, y)')
  print('d: ', d)
func()

輸出結果:

a:  None
b:  None
c:  None
10 20
d:  None

因為我們說過了,exec函式的返回值永遠為None。


例項2:

x = 10
expr = """
z = 30
sum = x + y + z
print(sum)
"""
def func():
  y = 20
  exec(expr)
  exec(expr, {'x': 1, 'y': 2})
  exec(expr, {'x': 1, 'y': 2}, {'y': 3, 'z': 4})
func()

輸出結果:

60
33
34


對輸出結果的解釋:


前兩個輸出跟上面解釋的eval函式執行過程一樣,不做過多解釋。關於最後一個數字34,我們可以看出是:x = 1, y = 3是沒有疑問的。關於z為什麼還是30而不是4,這其實也很簡單,我們只需要在理一下程式碼執行過程就可以了,其執行過程相當於:

x = 1
y = 2
def func():
  y = 3
  z = 4
  z = 30
  sum = x + y + z
  print(sum)
func()


相關文章