本文 AI 產出,尚未審核
Python 課程 – 例外與錯誤處理:錯誤追蹤(traceback 模組)
簡介
在開發 Python 程式時,**例外(Exception)**是不可避免的。即使我們已經用 try … except 把大多數錯誤捕捉住,仍有情況需要更深入的資訊來定位問題根源。此時,traceback 模組就派上用場——它能將例外發生時的呼叫堆疊完整地印出,讓開發者快速定位是哪一行、哪一個函式導致錯誤。
掌握 traceback 的使用方式,不僅能提升除錯效率,還能在 日誌(log) 中保留完整的錯誤資訊,方便事後分析與自動化監控。對於 初學者 來說,了解堆疊訊息的意義是學會「看錯誤」的第一步;對 中級開發者,則是建置可靠系統、實作自訂錯誤處理機制的基礎。
核心概念
1️⃣ 為什麼要使用 traceback?
- Python 內建的錯誤訊息已經會自動印出堆疊資訊,但在 捕捉例外後自行處理(例如寫入檔案、發送通知)時,原本的訊息會被隱藏。
traceback提供了 格式化、截取、轉換為字串 等多種 API,讓我們可以自行決定如何呈現或儲存錯誤資訊。
2️⃣ 常用的 traceback 函式
| 函式 | 功能說明 |
|---|---|
traceback.print_exc([limit], [file]) |
直接把目前捕捉到的例外堆疊印到 file(預設為 sys.stderr)。 |
traceback.format_exc([limit]) |
回傳堆疊的字串形式,常用於寫入日誌或回傳 API 錯誤。 |
traceback.extract_tb(tb, limit=None) |
從 Traceback 物件中抽取每一層的資訊(檔名、行號、函式名、文字)。 |
traceback.format_list(extracted_list) |
把 extract_tb 取得的列表轉成可讀的文字列表。 |
traceback.TracebackException |
Python 3.5+ 的物件導向介面,提供更彈性的堆疊資訊處理。 |
小技巧:在
except區塊內使用sys.exc_info()可以同時取得(type, value, traceback)三個元素,供traceback進一步處理。
3️⃣ 基本範例:印出完整堆疊
import traceback
def inner():
# 故意除以零,引發 ZeroDivisionError
return 1 / 0
def outer():
inner()
try:
outer()
except Exception as e:
# 直接印出完整的 traceback(等同於 Python 內建的錯誤輸出)
traceback.print_exc()
說明
traceback.print_exc()會自動抓取當前的例外資訊(等同於sys.exc_info()[2]),並將堆疊列印到標準錯誤輸出。- 執行結果會顯示
outer→inner的呼叫順序,幫助我們快速定位錯誤發生的地方。
4️⃣ 取得字串再自行處理
import traceback
import logging
def divide(a, b):
return a / b
try:
divide(10, 0)
except Exception:
# 把 traceback 轉成字串,寫入日誌檔
err_msg = traceback.format_exc()
logging.error("計算失敗:%s", err_msg)
說明
traceback.format_exc()回傳完整的堆疊文字,可直接傳給logging、寫入檔案或回傳給前端。- 使用
logging時,建議先設定適當的 日誌等級(如ERROR)與 檔案處理器,確保錯誤資訊不會遺失。
5️⃣ 只截取前幾層堆疊(限制深度)
在大型專案中,堆疊可能非常長,全部印出有時會過於雜訊。limit 參數讓我們只保留關鍵層級。
import traceback
def level1():
level2()
def level2():
level3()
def level3():
raise RuntimeError("故意觸發錯誤")
try:
level1()
except Exception:
# 只顯示最外層的兩層堆疊
print(traceback.format_exc(limit=2))
說明
limit=2只保留最外層的兩筆呼叫資訊(level1、level2),有助於在 log 中減少噪音。- 若不指定
limit,預設會顯示全部層級。
6️⃣ 使用 TracebackException 取得結構化資訊
import traceback
def foo():
bar()
def bar():
raise ValueError("參數錯誤")
try:
foo()
except Exception:
# 取得結構化的 TracebackException 物件
tb_exc = traceback.TracebackException(*sys.exc_info())
# 逐層列印
for line in tb_exc.format():
print(line, end='')
說明
TracebackException把例外與堆疊資訊封裝為物件,提供format()、stack、cause等屬性。- 這種方式在 自訂錯誤回報(例如產生 JSON 格式的錯誤訊息)時特別有用。
常見陷阱與最佳實踐
| 陷阱 | 可能的後果 | 建議的解法 |
|---|---|---|
直接 print(e) 而忽略堆疊 |
只能看到錯誤訊息,無法得知是哪裡拋出例外 | 使用 traceback.print_exc() 或 format_exc() 取得完整堆疊 |
在 except 中再次拋出相同例外,但未保留原始 traceback |
失去原始呼叫路徑,除錯變得困難 | 使用 raise(不加參數)或 raise new_exc from e 保留因果關係 |
| 將 traceback 寫入普通文字檔,卻未設定編碼或檔案模式 | 產生亂碼或寫入失敗 | 使用 open(..., encoding='utf-8'),或直接交給 logging 處理 |
在多執行緒/非同步環境下直接使用 sys.exc_info() |
可能抓不到正確的 traceback(因為例外在不同執行緒) | 在每個執行緒的 except 區塊內立即取得 traceback,或使用 concurrent.futures 的 exception() 方法 |
| 忘記限制 log 輸出大小 | 日誌檔過大,佔用磁碟空間 | 設定 logging.handlers.RotatingFileHandler,並結合 limit 參數縮減堆疊長度 |
最佳實踐
- 在捕捉例外的同一層立即取得 traceback,避免跨層傳遞時遺失資訊。
- 將 traceback 以字串形式寫入日誌,配合 時間戳記、模組名稱 等上下文,方便事後搜尋。
- 對外提供 API 時,僅回傳必要的錯誤訊息(例如錯誤代碼與簡短說明),將完整 traceback 只保留在伺服器端日誌。
- 使用
logging.exception():它會自動把當前例外的 traceback 加入日誌,寫法簡潔。import logging try: risky_operation() except Exception: logging.exception("執行 risky_operation 時發生錯誤") - 考慮將 traceback 轉成 JSON,配合監控平台(如 Sentry、Datadog)自動上報。
import traceback, json, sys exc_type, exc_value, exc_tb = sys.exc_info() tb_str = ''.join(traceback.format_exception(exc_type, exc_value, exc_tb)) payload = {"error": str(exc_value), "traceback": tb_str} send_to_monitoring(json.dumps(payload))
實際應用場景
| 場景 | 為什麼需要 traceback |
範例實作 |
|---|---|---|
| Web API 伺服器(Flask / FastAPI) | 當 API 發生未捕獲例外時,需要把完整錯誤寫入日誌,同時回傳通用的錯誤代碼給前端 | 在全域例外處理器中使用 logging.exception() 或 traceback.format_exc() |
| 背景工作(Celery、RQ) | 工作失敗時,管理介面會顯示簡短訊息,開發者需要從日誌中找出根本原因 | 在 task 的 except 中寫入 traceback.format_exc() 到 task.result |
| 資料處理腳本(ETL) | 大量資料處理時,單筆失敗不應中斷整體流程,但必須記錄失敗的行號與堆疊 | 捕捉例外後,把 traceback.format_exc() 寫入 CSV 或資料庫的錯誤表 |
| 測試自動化 | 單元測試失敗時,測試框架已提供堆疊,但自訂測試套件可能需要自行產生報告 | 使用 traceback.extract_tb 把堆疊轉成表格,寫入 HTML 測試報告 |
| 遠端除錯(SSH、Docker) | 容器內部發生錯誤,標準輸出可能被截斷,必須把堆疊寫入持久化儲存 | 在 except 中 open('/var/log/app_error.log', 'a', encoding='utf-8') 寫入 traceback.format_exc() |
總結
traceback是 Python 錯誤追蹤的核心工具,能將例外的呼叫堆疊以多種形式呈現。- 透過
print_exc、format_exc、TracebackException等 API,我們可以 即時印出、寫入日誌、或轉成結構化資料,滿足不同的除錯需求。 - 在實務開發中,立即捕捉並記錄 traceback 是保證系統可觀測性與維護性的關鍵;同時,適度 限制堆疊深度、避免洩漏敏感資訊 也是必須注意的安全考量。
- 結合
logging、json、監控平台等技術,能把 traceback 變成 可搜尋、可告警、可視化 的資產,讓開發與運維團隊在問題發生時快速定位、迅速回復。
掌握了 traceback,你就不再只是「看到錯誤訊息」的被動觀察者,而是能 主動追蹤、分析、記錄 的除錯高手。祝你在 Python 的例外處理之路上,越走越順! 🚀