本文 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]),並將堆疊列印到標準錯誤輸出。
  • 執行結果會顯示 outerinner 的呼叫順序,幫助我們快速定位錯誤發生的地方。

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 只保留最外層的兩筆呼叫資訊(level1level2),有助於在 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()stackcause 等屬性。
  • 這種方式在 自訂錯誤回報(例如產生 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.futuresexception() 方法
忘記限制 log 輸出大小 日誌檔過大,佔用磁碟空間 設定 logging.handlers.RotatingFileHandler,並結合 limit 參數縮減堆疊長度

最佳實踐

  1. 在捕捉例外的同一層立即取得 traceback,避免跨層傳遞時遺失資訊。
  2. 將 traceback 以字串形式寫入日誌,配合 時間戳記模組名稱 等上下文,方便事後搜尋。
  3. 對外提供 API 時,僅回傳必要的錯誤訊息(例如錯誤代碼與簡短說明),將完整 traceback 只保留在伺服器端日誌。
  4. 使用 logging.exception():它會自動把當前例外的 traceback 加入日誌,寫法簡潔。
    import logging
    try:
        risky_operation()
    except Exception:
        logging.exception("執行 risky_operation 時發生錯誤")
    
  5. 考慮將 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) 容器內部發生錯誤,標準輸出可能被截斷,必須把堆疊寫入持久化儲存 exceptopen('/var/log/app_error.log', 'a', encoding='utf-8') 寫入 traceback.format_exc()

總結

  • traceback 是 Python 錯誤追蹤的核心工具,能將例外的呼叫堆疊以多種形式呈現。
  • 透過 print_excformat_excTracebackException 等 API,我們可以 即時印出、寫入日誌、或轉成結構化資料,滿足不同的除錯需求。
  • 在實務開發中,立即捕捉並記錄 traceback 是保證系統可觀測性與維護性的關鍵;同時,適度 限制堆疊深度避免洩漏敏感資訊 也是必須注意的安全考量。
  • 結合 loggingjson、監控平台等技術,能把 traceback 變成 可搜尋、可告警、可視化 的資產,讓開發與運維團隊在問題發生時快速定位、迅速回復。

掌握了 traceback,你就不再只是「看到錯誤訊息」的被動觀察者,而是能 主動追蹤、分析、記錄 的除錯高手。祝你在 Python 的例外處理之路上,越走越順! 🚀