eval()用于計算表達式并返回結果,exec()用于執行語句塊且不返回值。1.eval()處理單個表達式并返回值,如數學運算或字典解析;exec()執行多行代碼或語句塊,如賦值、函數定義等。2.eval()會返回表達式的結果,而exec()僅執行操作無返回值。3.兩者均存在安全風險,若執行不可信輸入可能導致系統破壞或數據泄露,應避免處理用戶輸入,或限制命名空間及使用ast.literal_eval()替代。4.eval()適用于計算表達式,exec()適合動態創建函數或執行腳本。
在 python 中,eval() 和 exec() 都是用來動態執行字符串形式的代碼,但它們適用的場景和功能有明顯區別。簡單來說,eval() 用于計算表達式并返回結果,而 exec() 用于執行語句塊,不返回值。如果你只是想運行一段動態生成的代碼,用 exec() 更合適;如果只是想求一個表達式的值,比如數學運算或變量替換,就用 eval()。
下面從幾個角度講清楚兩者的差異和潛在風險。
1. 基本功能差異:表達式 vs 語句
-
eval() 只能處理表達式(expression),也就是說它只能執行會返回一個值的代碼。例如:
result = eval("2 + 3 * 5") print(result) # 輸出 17
-
exec() 能處理完整的語句塊(statements),包括賦值、函數定義、循環等。例如:
立即學習“Python免費學習筆記(深入)”;
code = """ a = 10 b = 20 print(a + b) """ exec(code) # 輸出 30
所以如果你要運行多行代碼或者修改變量狀態,只能用 exec()。
2. 返回值的區別:有沒有結果
-
eval() 會返回表達式的結果。例如:
value = eval("{'name': 'Tom', 'age': 25}") print(type(value)) # <class 'dict'>
-
exec() 不返回值(返回的是 None),它的作用是“做事情”,而不是“算結果”。比如你可以用它來定義函數:
exec("def say_hello(): print('Hello!')") say_hello() # 輸出 Hello!
3. 安全風險:不要輕易執行不可信輸入
這兩個函數最大的問題就是——它們可以執行任意代碼。如果用戶輸入的內容被當作參數傳給 eval() 或 exec(),那就可能帶來嚴重的安全隱患。
常見風險舉例:
-
刪除文件、修改系統設置等破壞性操作:
# 想象用戶輸入了這樣的字符串 user_input = "__import__('os').system('rm -rf /')" # 如果你用了 eval 或 exec 執行這個字符串……后果嚴重
-
獲取敏感信息、泄露數據:
# 用戶構造輸入讀取密碼變量 user_input = "password"
如何降低風險?
-
盡量避免使用 eval() 和 exec() 處理用戶輸入。
-
如果一定要用,限制命名空間,禁用內置模塊:
safe_globals = {"__builtins__": None} # 禁用所有內置函數 exec("print('hello')", safe_globals) # 會報錯,無法執行
-
使用更安全的替代方案,比如 ast.literal_eval() 來解析字符串中的字面量(如列表、字典):
import ast data = ast.literal_eval("{'name': 'Tom', 'age': 25}") print(data) # 安全地轉為 dict
4. 什么時候該用哪個?常見使用場景
場景 | 推薦使用 | 說明 |
---|---|---|
計算數學表達式 | eval() | 比如計算器程序解析輸入 |
解析字符串成結構化數據 | ast.literal_eval() | 比如解析 json 字符串 |
動態創建函數或類 | exec() | 運行時根據配置生成邏輯 |
執行用戶自定義腳本 | exec() | 但要注意權限控制 |
基本上就這些。eval() 和 exec() 都很強大,但也容易出問題。用的時候要清楚自己在干什么,尤其是面對外部輸入時,千萬不能掉以輕心。