
新手與資深工程師最大的差別之一,就是除錯 (Debugging) 的效率。
新手遇到 bug 只會 print("Check 1"), print("Check 2")。而資深工程師會看 Log,或者直接開 Debugger 進入程式內部檢查。
1. 為什麼不要用 print()?
- 分級困難:你無法輕易開關特定的 print (例如只在開發時顯示,上線後隱藏)。
- 效能問題:大量的 print I/O 會拖慢程式。
- 缺乏資訊:print 只有你寫的訊息,沒有時間戳記、檔案名稱、行號等上下文。
2. Python Logging 模組
Python 內建的 logging 模組非常強大。
基礎用法
import logging
# 設定日誌等級與格式
logging.basicConfig(
level=logging.INFO, #設定最低顯示等級
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logging.debug("這是一條 Debug 訊息 (不會顯示)")
logging.info("系統啟動中...") # 這是 INFO
logging.warning("磁碟空間不足")
logging.error("資料庫連線失敗!")
logging.critical("系統崩潰!")
輸出結果
2024-01-17 10:00:00,123 - root - INFO - 系統啟動中...
2024-01-17 10:00:00,124 - root - WARNING - 磁碟空間不足
...
進階:寫入檔案 (FileHandler)
通常我們希望 Error 寫入檔案,Info 顯示在螢幕。
logger = logging.getLogger("my_app")
logger.setLevel(logging.DEBUG)
# 檔案處理器 (寫入 app.log)
file_handler = logging.FileHandler("app.log")
file_handler.setLevel(logging.ERROR) # 只記錄錯誤以上
# 串流處理器 (顯示在 Console)
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.INFO)
logger.addHandler(file_handler)
logger.addHandler(stream_handler)
logger.info("這會顯示在螢幕,不會寫入檔案")
logger.error("這會顯示在螢幕,並寫入 app.log")
3. PDB:Python Debugger
當 Log 看不出原因時,我們需要「讓程式停下來」,檢查當下的變數狀態。
斷點 (Breakpoint)
在 Python 3.7+,只要在想暫停的地方加一行:
def complex_calculation(x, y):
z = x * y
breakpoint() # 程式跑這這裡會暫停,進入互動模式
return z + 10
complex_calculation(5, 0)
當程式暫停時,你會看到 (Pdb) 提示符號。常用指令:
n(next): 執行下一行。s(step): 進入函式內部。c(continue): 繼續執行直到下個斷點。p variable_name: 印出變數值 (例如p z)。l(list): 顯示目前程式碼片段。q(quit): 強制退出。
ipdb: 更好用的 Debugger
Pdb 的介面有點陽春。推薦安裝 ipdb (pip install ipdb),它有語法高亮和自動補全。
用法一模一樣,只是改成 import ipdb; ipdb.set_trace() (或者在 code 中設 breakpoint() 並設定環境變數 PYTHONBREAKPOINT=ipdb.set_trace)。
4. 總結
除錯是寫程式的一部分。
- Logging: 留下記錄,讓你事後能追查凶手 (適合 Production 環境)。
- Debugger: 現場開刀,即時檢視病灶 (適合 Development 環境)。
下一章,也是 Batch 7 的最後一章,我們將學習如何讓你的程式跑得飛快——效能分析與優化 (Profiling)!
延伸閱讀: