eval() 的強大在於它會把你輸入的東西「當成程式碼來執行」。這雖然很靈活,但也很危險。
假設你這樣寫程式:
a, b, c = eval(input("input: "))
然後你在輸入的時候,不是輸入 (1, 2, 3),而是輸入這段文字:
(1, 2, __import__('os').system('echo 危險動作已執行'))
危險動作已執行
這是因為:
__import__('os') 會載入 os 模組(系統操作)
.system(...) 可以執行系統指令(像是在終端機輸入指令)
這裡執行的是 echo 危險動作已執行,但如果是:
__import__('os').system('rm -rf /')
就可能直接刪光電腦裡的東西 😱(幸好大部分作業系統會擋)
a, b, c = map(int, input("請輸入三個整數,用空格分隔: ").split())
這樣只會解析使用者輸入的「值」,不會執行任何指令。
自己寫程式自己用、完全知道輸入是什麼 的時候(例如練習中)
快速測試 表達式、數學式
但只要有「用戶輸入」,基本上就該避免 eval()
「安全但觀察得到危險性」 的小練習!這樣你可以體會 eval() 的威力,但又不會造成損害 🔍🔥
# 2025/04/04-20:50
while True:
expr = input("請輸入數學式(或輸入 'exit' 離開): ")
if expr == "exit":
break
try:
result = eval(expr)
print("計算結果:", result)
except:
print("發生錯誤,請輸入正確的算式!")
請輸入數學式(或輸入 'exit' 離開): 1 + 2 * 3
計算結果: 7
請輸入數學式(或輸入 'exit' 離開): (10/2)**2
計算結果: 25.0
請輸入數學式(或輸入 'exit' 離開): exit
__import__('os').system('echo 👀 你在執行系統指令')
結果會在終端機印出:
複製編輯
👀 你在執行系統指令
這樣就能清楚看到:輸入的不是算式,而是程式碼,而 eval() 還是會照單全收!
如果真的想寫「計算器」功能但又怕風險,可以這樣做:
import ast
expr = input("輸入簡單數學式:")
node = ast.parse(expr, mode='eval')
for n in ast.walk(node):
if not isinstance(n, (ast.Expression, ast.BinOp, ast.UnaryOp, ast.Num, ast.Add, ast.Sub, ast.Mult, ast.Div, ast.Pow, ast.Mod)):
raise ValueError("只允許數學基本運算!")
print(eval(expr))
這段程式會先用 ast(抽象語法樹)檢查語法安全性,只允許基本運算。