プログラミングをしていると、エラー(例外)が発生したときに「どこで何が問題だったのか」を素早く把握したいものです。
Python 標準ライブラリの traceback モジュールは、例外発生時のスタックトレース(コールスタック)を取得・整形・出力する機能を提供し、デバッグ作業を効率化してくれます。
本記事では、初心者の方を対象に traceback モジュールの基本的な使い方から応用例までを丁寧に解説します。
traceback モジュールとは?
traceback モジュールは、プログラムの例外発生時に自動的に出力されるトレースバック情報を、プログラム内から操作・取得できるライブラリです。
主な用途は以下のとおりです。
- トレースバックを文字列として取得
- トレースバックをファイルへ保存
- カスタムフォーマットで整形して出力
基本的な使い方
例外発生時の標準トレースバック
def divide(a, b):
return a / b
def main():
result = divide(10, 0)
if __name__ == "__main__":
main()
上記を実行すると、以下のようにエラー情報が自動出力されます。
Traceback (most recent call last):
File "example.py", line 8, in <module>
main()
File "example.py", line 5, in main
result = divide(10, 0)
File "example.py", line 2, in divide
return a / b
ZeroDivisionError: division by zero
traceback.format_exc() で文字列取得
import traceback
try:
1 / 0
except ZeroDivisionError:
tb_str = traceback.format_exc()
print("取得したトレースバック文字列:")
print(tb_str)
format_exc() は例外情報を文字列で返します。
ログファイルや、ウェブアプリのエラーページなどに埋め込むのに便利です。
トレースバックをファイルに書き出す
import traceback
def log_error_to_file():
try:
int("abc")
except Exception:
with open("error.log", "w") as f:
traceback.print_exc(file=f)
if __name__ == "__main__":
log_error_to_file()
print("error.log にエラー情報を書き込みました。")
traceback.print_exc(file=…) で、トレースバックを任意のファイルオブジェクトに出力できます。
ログ管理の自動化に役立ちます。
カスタムフォーマットで整形
traceback.extract_tb() を使うと、トレースバック情報をリスト形式で扱えます。
import traceback
def func_a():
func_b()
def func_b():
1 / 0
try:
func_a()
except Exception as e:
tb_list = traceback.extract_tb(e.__traceback__)
for frame in tb_list:
filename, lineno, funcname, text = frame
print(f"ファイル『{filename}』の {lineno} 行目、関数 {funcname} でエラー。該当コード: {text}")
出力例
ファイル『example.py』の 5 行目、関数 func_b でエラー。該当コード: 1 / 0
ファイル『example.py』の 2 行目、関数 func_a でエラー。該当コード: func_b()
応用例:ウェブアプリでのエラー表示
import traceback
from flask import Flask, request
app = Flask(__name__)
@app.errorhandler(Exception)
def handle_exception(e):
# トレースバックをHTMLで返す
tb_html = "<pre>" + traceback.format_exc() + "</pre>"
return tb_html, 500
@app.route("/")
def index():
return str(1 / 0) # 故意にエラー
if __name__ == "__main__":
app.run(debug=False)
debug=False の本番環境でも、独自のエラーハンドラで詳細情報を取得できます。
format_exc() を <pre> タグでラップすると、見やすいHTML表示になります。
まとめ
- traceback.format_exc():文字列としてトレースバックを取得
- traceback.print_exc():ファイルや標準出力に出力
- traceback.extract_tb():トレースバックを構造化して取得
これらを組み合わせることで、デバッグログの自動化や、ユーザーへのエラー表示が柔軟に行えます。初心者のうちから身につけておくと、開発効率が大きく向上します。
演習問題
問題1
関数 read_int_from_file(path) を作成し、指定された path のファイルから1行目を読み込み、整数に変換して返す関数を実装してください。
- ファイルが存在しない場合(FileNotFoundError)は “ファイルが見つかりません: {path}” と表示し、None を返す。
- 整数変換に失敗した場合(ValueError)は “整数への変換に失敗しました: {読み込んだ文字列}” と表示し、None を返す。
- それ以外の例外が発生した場合は、traceback.format_exc() で取得したトレースバックを error.log に書き込み、None を返す。
問題2
問題1の関数を呼び出す main() を作成し、戻り値が None でない場合は “読み込んだ整数: {値}” と表示してください。さらに、意図的に文字列が書かれたファイルを読み込ませて動作を確認してください。
解答例
import traceback
def read_int_from_file(path):
try:
with open(path, "r") as f:
line = f.readline().strip()
return int(line)
except FileNotFoundError:
print(f"ファイルが見つかりません: {path}")
return None
except ValueError:
print(f"整数への変換に失敗しました: {line}")
return None
except Exception:
with open("error.log", "w") as logf:
logf.write(traceback.format_exc())
return None
def main():
paths = ["exists_int.txt", "exists_str.txt", "no_file.txt"]
for p in paths:
result = read_int_from_file(p)
if result is not None:
print(f"読み込んだ整数: {result}")
if __name__ == "__main__":
main()
解説
- FileNotFoundError、ValueError は個別にキャッチしてユーザー向けメッセージを表示。
- それ以外の例外は汎用 except Exception でキャッチし、traceback.format_exc() による詳細情報を error.log に記録。
- main() で複数のケースを試すことで、各例外処理が正しく動作することを確認できます。
以上で、初心者向けの traceback モジュール入門は完了です。エラー発生箇所の特定やログ保存を習慣化して、より強固なデバッグスキルを身につけましょう!