Python exec()和eval()的使用注意事項

2020-07-16 10:05:01
使用 exec() 和 eval() 函數時,一定要記住,它們的第一個引數是字串,而字串的內容一定要是可執行的程式碼。

以 eval() 函數為例,用程式碼演示常犯的錯誤:
s="hello"
print(eval(s))
輸出結果為:

Traceback (most recent call last):
  File "C:UsersmengmaDesktopdemo.py", line 2, in <module>
    print(eval(s))
  File "<string>", line 1, in <module>
NameError: name 'hello' is not defined

上面例子出錯的地方在於,字串的內容是 hello,而 hello 並不是可執行的程式碼(除非定義了一個變數叫作 hello)。

如果要將字串 hello 通過 print 函數列印出來,可以寫成如下的樣子:
s="hello"
print(eval('s'))
輸出結果為:

hello

這種寫法是要 eval() 執行 "hello" 這句程式碼。這個 hello 是有引號的,在程式碼中代表字串的意思,所以可以執行。

同理,也可以寫成這樣:
s='"hello"' #s 是個字串,字串的內容是帶引號的 hello
print(eval(s))
輸出結果為:

hello

這種寫法的意思是 s 是個字串,並且其內容是個帶引號的 hello。所以直接將 s 放入到函數 eval() 中也可以執行。

除了以上這種方式,還可以不去改變原有字串 s 的寫法,直接使用 repr() 函數來進行轉化,也可以得到同樣的效果。例如:
s="hello"
print(eval(repr(s))) #使用函數 repr() 進行轉化
輸出結果為:

hello


注意,雖然函數 eval() 與 str() 的返回值都是字串。但是使用 str() 函數對 s 進行轉化,程式同樣會報錯,例如:
s="hello"
print(eval(str(s)))
輸出結果為:

Traceback (most recent call last):
  File "C:UsersmengmaDesktopdemo.py", line 2, in <module>
    print(eval(str(s)))
  File "<string>", line 1, in <module>
NameError: name 'hello' is not defined

為什麼會有這個區別呢?同樣對帶字串 s 的轉化,使用 repr() 與 str() 得到的結果是有差別的,直接將二者的結果列印出來,就可以很明顯地看出不同。見下面程式碼:
s="hello"
print(repr(s))
print(str(s))
輸出結果為:

'hello'
hello

可見使用 repr() 返回的內容,輸出後會在兩邊多一個單引號。

注意,在編寫程式碼時,一般會使 repr() 數來生成動態的字串,再傳入到 eval() 或 exec() 函數內,實現動態執行程式碼的功能。