Python 提供多種結束程式或函式的方式,行為差異巨大。本文透過實戰案例詳細對比 return、exit()、sys.exit()、os._exit() 的運作機制、適用場景與常見陷阱。
| 方式 | 層級 | 機制 | 可被捕獲 | finally 執行 | 適用場景 |
|---|---|---|---|---|---|
return | 函式 | 返回呼叫者 | 否 | 是 | 正常函式返回 |
exit() / quit() | 進程 | 拋出 SystemExit | 是 | 是 | 互動式環境退出 |
sys.exit() | 進程 | 拋出 SystemExit | 是 | 是 | 腳本正常結束 |
os._exit() | 進程 | 直接系統呼叫 | 否 | 否 | 子進程緊急結束 |
#!/usr/bin/env python
import sys
import keyword
import string
key_words = keyword.kwlist
char_for_id = string.letters + "_"
num_for_id = string.digits
identifier = raw_input("Input your words, please! ")
if identifier in key_words:
print("%s is keyword for Python!" % identifier)
else:
if len(identifier) == 1:
if identifier in char_for_id and identifier != "_":
print("%s is legal identifier!" % identifier)
else:
print("%s isn't legal identifier!" % identifier)
else:
if identifier[0] in char_for_id:
legal_chars = char_for_id + num_for_id
for ch in identifier[1:]:
if ch not in legal_chars:
print("%s isn't legal identifier!" % identifier)
sys.exit(0) # 關鍵:這裡想直接結束程式
print("%s is legal identifier!" % identifier)
else:
print("%s isn't legal identifier!" % identifier)
$ python idcheck.py
Input: _d4%
_d4% isn't legal identifier!
Traceback (most recent call last):
File "idcheck.py", line 37, in
sys.exit(0)
SystemExit: 0
問題:sys.exit() 拋出 SystemExit 異常,若未捕獲會顯示堆疊追蹤,輸出不乾淨。
try:
# ... 主要邏輯 ...
if invalid:
print("Invalid!")
sys.exit(1)
except SystemExit:
pass # 靜默吞沒,程式乾淨退出
except Exception:
traceback.print_exc() # 其他真正錯誤仍顯示堆疊
# 在迴圈中
for item in items:
if bad(item):
print("Bad!")
exit() # 僅跳出迴圈?否!同樣拋出 SystemExit 結束整個程式
# 但 exit 是 site 模組注入的別名,非關鍵字
# 在無 site 模組環境 (python -S) 不可用
結論:exit() 與 sys.exit() 行為相同 (皆拋出 SystemExit),不會 只跳出迴圈。若需跳出迴圈請用 break。
def validate(identifier):
if not identifier:
return False # 返回呼叫者
# ...
return True
# 主程式
if not validate(user_input):
sys.exit(1) # 在主流程用 sys.exit 結束程式
_exit(),不執行 finally、不刷新緩衝區、不呼叫 atexit 處理器。fork() 後的子進程避免雙重清理資源。return。sys.exit(0)) 或明確 sys.exit(0)。sys.exit(1) 或非零代碼,並配合 try/except SystemExit 避免堆疊追蹤。exit()/quit() 或 Ctrl+D。os._exit()。with/try/finally/atexit,確保 sys.exit() 觸發時仍能釋放資源。