try-except 文で例外を捕捉し、print(e) でエラー内容を表示するだけでは、大規模なプログラムのデバッグには不十分な場合があります。単純なエラーメッセージだけでは、「具体的にどのファイルの、どの行で、どの関数を経由してエラーが発生したのか」という経路情報(スタックトレース)がわからないためです。
Pythonの標準ライブラリである traceback モジュールを使用すると、このスタックトレースを取得・表示することができます。これは、エラーログをファイルに保存したり、管理者に通知を送ったりする際に不可欠な機能です。
この記事では、traceback モジュールを使って例外の詳細情報を取得する方法について解説します。
print(e) だけでは足りない場合
通常、except Exception as e: として例外を捕捉し print(e) を実行すると、エラーの「種類」と「短いメッセージ」のみが表示されます。
try:
# リストの範囲外アクセスなどのエラー
my_list = [10, 20]
print(my_list[5])
except IndexError as e:
print(f"エラーが発生しました: {e}")
実行結果:
エラーが発生しました: list index out of range
これだけでは、プログラムのどの部分でこのエラーが発生したのか、即座に特定するのは困難です。特に、関数がいくつも呼び出されている深い階層でエラーが起きた場合には、原因究明に時間がかかります。
traceback モジュールの基本
traceback モジュールを使用すると、Pythonがクラッシュした際に表示されるような詳細なエラー情報を、プログラムを停止させずに取得できます。
traceback.format_exc():文字列として取得
最も汎用的なのが traceback.format_exc() です。これは現在発生している例外のスタックトレースを文字列として返します。文字列なので、ログファイルへの書き込みや、データベースへの保存に適しています。
構文:
import traceback
try:
# 処理
except Exception:
# 詳細なエラー情報を文字列で取得
error_log = traceback.format_exc()
print(error_log)
実践的なコード例:深い階層のエラー追跡
関数が入れ子になって呼び出されている状況で、最深部でエラーが発生した場合のトレースバックを確認します。
例として、データ分析のパイプライン処理を模したプログラムを作成します。
import traceback
def load_data():
"""データを読み込む関数(ここでエラー発生)"""
# 意図的に未定義の変数を参照して NameError を発生させる
return raw_data_buffer
def process_data():
"""データを加工する関数"""
print("データ加工を開始...")
load_data()
print("データ加工を終了")
def main_pipeline():
"""メイン処理"""
print("--- 処理開始 ---")
try:
process_data()
except Exception:
# tracebackを使って詳細情報を取得・表示
print("予期せぬエラーが発生しました。詳細ログを出力します。\n")
# エラー詳細(スタックトレース)を取得
tb_msg = traceback.format_exc()
# 実際にはここでログファイルへの書き込みなどを行う
print("---------------- ERROR LOG ----------------")
print(tb_msg)
print("-------------------------------------------")
print("--- 処理終了(システムは停止していません) ---")
# 実行
main_pipeline()
実行結果:
--- 処理開始 ---
データ加工を開始...
予期せぬエラーが発生しました。詳細ログを出力します。
---------------- ERROR LOG ----------------
Traceback (most recent call last):
File "script.py", line 16, in main_pipeline
process_data()
File "script.py", line 11, in process_data
load_data()
File "script.py", line 6, in load_data
return raw_data_buffer
NameError: name 'raw_data_buffer' is not defined
-------------------------------------------
--- 処理終了(システムは停止していません) ---
traceback.format_exc() を使用したことで、「main_pipeline が process_data を呼び、それが load_data を呼び、そこで NameError が発生した」という一連の流れ(トレース)が記録されました。これにより、バグの特定が容易になります。
traceback.print_exc() との使い分け
文字列として取得するのではなく、単に標準エラー出力(コンソール)に表示するだけでよい場合は、traceback.print_exc() を使用すると簡潔に記述できます。
try:
# エラー処理
int("文字")
except ValueError:
# format_exc() で文字列取得して print() するのと同じ結果
traceback.print_exc()
format_exc(): 文字列として取得したい場合(ログ保存、メール送信など)。print_exc(): とりあえず画面に表示したい場合(開発中のデバッグなど)。
まとめ
- 例外の発生箇所や経路(スタックトレース)を知るには、標準ライブラリの
tracebackモジュールを使用します。 traceback.format_exc()を使うと、スタックトレースを文字列として取得できます。- ログファイルへの記録や、エラー監視システムへの通知を行う際には、単なる
eではなく、この詳細情報を記録することが重要です。
