Pythonでエラースタックトレースを表示・取得する方法を徹底解説!初心者向け例外処理入門
生徒
「Pythonのプログラムがエラーになると、長い英語のメッセージと数字がたくさん出てきて、正直よく分からないんです。あの細かい表示って何なんでしょうか?」
先生
「あの長い表示はスタックトレースと呼ばれていて、エラーがどこで起きたのかを教えてくれるとても大事な情報なんです。Pythonの例外処理やデバッグでは欠かせない仕組みですよ。」
生徒
「スタックトレースって名前も難しそうですし、自分で表示したり保存したりできるんですか?画面に出るだけだともったいない気がします。」
先生
「もちろんできますよ。Pythonにはtracebackという標準モジュールが用意されていて、自分でスタックトレースを表示したり文字列として取得したり、ログファイルに残したりできます。仕組みが分かると例外処理が一気に扱いやすくなりますよ。」
1. スタックトレースとは?Pythonのエラーの足跡を追いかける情報
スタックトレースとは、プログラムがエラーで止まったときに「どの関数(命令のまとまり)をどんな順番で実行して、最終的にどこで力尽きてしまったのか」を逆送して教えてくれるレポートのようなものです。Pythonのエラーメッセージで、ファイル名や行番号がずらっと並んでいる部分がまさにそれです。迷子になったときに、自分が歩いてきた道を地図で振り返るようなイメージを持つと理解しやすくなります。
スタックトレースは、一番下が「エラーの直接の原因」で、上に向かって「それを呼び出した場所」が記録されています。
プログラミング未経験の方にとって、英語ばかりの長い表示は「叱られている」ように見えて怖いかもしれません。しかし、実際は「ここでつまずいたよ!原因はこのファイルの〇行目だよ!」というPythonからの親切なアドバイスです。スタックトレースを読み解くことができれば、どこを直せばいいのかが秒速で分かるようになります。
例えば、次のような「挨拶をしてから計算をする」という単純な流れでエラーが起きた場合を見てみましょう。
def start_app():
# 1. 挨拶をする関数を呼ぶ
say_hello()
def say_hello():
# 2. 計算をする関数を呼ぶ
calculate_data()
def calculate_data():
# 3. ここでわざとエラー(0で割り算)を発生させる
print(10 / 0)
# プログラム開始!
start_app()
このコードを実行すると、スタックトレースには「start_appの中でsay_helloを呼び、その中でcalculate_dataを呼び、そこでエラーが起きた」という経緯がすべて記録されます。このように、処理が積み重なった(スタックされた)記録を追跡(トレース)するから「スタックトレース」と呼びます。例外処理を学ぶ第一歩として、この「エラーの家系図」のような情報を味方につけることで、トラブル解決能力が格段にアップします。
2. 例外がそのまま発生したときのスタックトレース表示
まずは、スタックトレースが何もしなくても自動で表示されるケースを確認しましょう。Pythonでは、tryで囲まれていない場所で例外が発生すると、インタプリタが自動的にスタックトレースを画面に表示します。これはデバッグ中には便利ですが、実際のアプリケーションではユーザーにそのまま見せたくない場合も多く、しっかりとしたエラーハンドリングが必要になります。
def divide(a, b):
return a / b
result = divide(10, 0)
print(result)
このコードを実行すると、ZeroDivisionErrorとともにスタックトレースが自動的に表示されます。どの行でdivide関数が呼び出され、どこでエラーになったかが一覧になって出力されます。ここまではPythonが自動で行ってくれる標準的な動きですが、現場ではこの情報を自分の好きなタイミングで表示したりログに残したりしたくなります。そのときに使うのがtracebackモジュールです。
3. traceback.print_excでスタックトレースを明示的に表示する
スタックトレースを自分で表示したいときには、traceback.print_excという関数を使います。これはtryとexceptで例外をキャッチしたあとでも、元のスタックトレースをきれいな形式で出力してくれる便利な関数です。例外を握りつぶしてしまわず、開発者向けには詳しい情報を残したいときにとても役立ちます。
import traceback
def divide(a, b):
return a / b
try:
result = divide(10, 0)
print(result)
except Exception:
print("エラーが発生しました。詳細はスタックトレースを確認してください。")
traceback.print_exc()
このように書くと、ユーザーには簡単なメッセージを表示しつつ、開発者はtraceback.print_excの出力から詳しいエラー位置を確認できます。例外オブジェクトを直接扱わなくても使えるため、初心者の方にも扱いやすい関数です。スタックトレースを画面に出してデバッグしたい場合には、まずこの書き方から慣れていくとよいでしょう。
4. traceback.format_excでスタックトレースを文字列として取得する
スタックトレースを単に表示するだけでなく、文字列として取得したい場面もあります。例えば、ログファイルに書き込んだり、メールで通知したり、画面には見せずに内部で保存したいケースです。そのようなときに便利なのがtraceback.format_excです。printではなくformatという名前の通り、スタックトレースを整形済みのテキストとして返してくれます。
import traceback
def divide(a, b):
return a / b
def main():
try:
result = divide(10, 0)
print(result)
except Exception:
error_text = traceback.format_exc()
with open("error.log", "a", encoding="utf-8") as f:
f.write(error_text)
print("エラーの詳細をログファイルに保存しました。")
main()
このサンプルでは、スタックトレースを文字列として受け取り、error.logというファイルに追記しています。後から落ち着いてファイルを開けば、どの関数のどの行でエラーが発生したのか一目で分かります。Pythonの例外処理とログ設計を組み合わせることで、実運用に耐えるエラーハンドリングが可能になります。
5. loggingモジュールと組み合わせてスタックトレースを記録する
さらに一歩進んだ使い方として、loggingモジュールとtracebackを組み合わせるパターンがあります。loggingにはexc_infoという引数があり、これを使うと例外情報付きのログを簡単に出力できます。スタックトレースも含めてエラーログを残したいときには、この仕組みを活用するとシンプルなコードで分かりやすいログを残せます。
import logging
logging.basicConfig(
level=logging.ERROR,
filename="app.log",
format="%(asctime)s [%(levelname)s] %(message)s",
encoding="utf-8"
)
def divide(a, b):
return a / b
try:
result = divide(10, 0)
print(result)
except Exception:
logging.error("計算中にエラーが発生しました", exc_info=True)
このように書くと、app.logの中にエラーメッセージとスタックトレースがまとめて記録されます。traceback.format_excを自分で呼び出さなくても、exc_info=Trueを指定するだけでよいのがポイントです。小さなスクリプトでは画面出力だけでも足りますが、少し規模が大きくなってきたら、ログファイルとスタックトレースを活用する構成に切り替えていくと安心です。
6. 初心者がスタックトレースを扱うときに意識したいポイント
最後に、Pythonのスタックトレースを扱うときに初心者が意識しておくと便利なポイントをまとめます。まず、スタックトレースは怖いものではなく、エラーの場所を教えてくれる頼もしい味方だと捉えることが大切です。表示された行番号や関数名を一つずつ追いかけるだけでも、バグの原因に近づくことができます。慣れてくると、どんな例外が出ても落ち着いて対処できるようになります。
また、実際の現場では、ただエラーを表示するだけでなく、スタックトレースをきちんと保存しておくことが求められます。traceback.print_excで画面に表示する方法、traceback.format_excで文字列として取得する方法、loggingモジュールと組み合わせてログファイルに残す方法など、自分の用途に合ったパターンを少しずつ身につけていきましょう。Pythonの例外処理とスタックトレースの取り扱いに慣れておくと、プログラムの品質と信頼性を大きく高めることができます。