Pythonのエラーに出会ったとき、長い英語の文字列に圧倒されていませんか。
実はTracebackは読み方の順番さえ分かれば、原因の特定が一気に楽になります。
本記事では一番下から読むことを合言葉に、基本の見方、ケース別のコツ、そして初心者向けの直し方を丁寧に解説します。
Tracebackとは?Pythonのエラーメッセージの基本
Tracebackの意味と役割
Pythonでプログラム実行中にエラー(例外)が起きると、実行を停止してTraceback
というメッセージを表示します。
これはエラー発生地点までの関数呼び出しの履歴(スタックトレース)です。
各行にはファイル名、行番号、該当のコード行が並び、最後に例外の種類とメッセージが表示されます。
Tracebackが出るのは、例外をtry
で捕まえずに伝播し、処理系まで届いたときです。
“Traceback (most recent call last)” の意味
Tracebackの先頭にはTraceback (most recent call last)
と表示されます。
これはここから最新の呼び出しに遡って並べますという合図です。
上から古い呼び出し、下に行くほど新しい呼び出しが現れ、最後に例外の種類が出ます。
先頭ではなく一番下が決定的に重要です。
以下は簡単な例です。
# example_zero_division.py
# 関数が入れ子になった末に0除算が発生する例
def a():
# 0で割るとZeroDivisionErrorが発生します
return 1 / 0
def b():
# aを呼び出すだけの関数
return a()
# 実行開始
b()
Traceback (most recent call last):
File "example_zero_division.py", line 13, in <module>
b()
File "example_zero_division.py", line 9, in b
return a()
File "example_zero_division.py", line 5, in a
return 1 / 0
ZeroDivisionError: division by zero
例外タイプとエラーメッセージの読み分け
最後の行には例外タイプ(例: ZeroDivisionError
)とエラーメッセージ(例: division by zero
)が表示されます。
タイプは原因の大分類、メッセージは具体的な手がかりです。
初心者のうちはこの2つをそのまま検索すると有力な情報に辿り着きやすいです。
代表的な例外とヒントをまとめます。
例外タイプ | よくある原因 | まず試すこと |
---|---|---|
NameError | 変数名や関数名のスペルミス、定義前参照 | 名前の定義場所とスコープを確認。タイポ修正。 |
TypeError | 引数個数違い、型の取り違い | 関数のシグネチャ確認。型をprint(type(...)) で確認。 |
ValueError | 値の内容が不正 | 入力値の前処理やバリデーションを追加。 |
KeyError | 辞書にキーが存在しない | dict.keys() を確認。get でデフォルトを使う。 |
IndexError | リストの範囲外アクセス | 長さとインデックスを確認。空リストに注意。 |
AttributeError | オブジェクトに属性がない | dir(obj) で存在確認。チェーンの途中がNone でないか確認。 |
ModuleNotFoundError | モジュールが見つからない | パッケージ名とインストール環境を確認。スペルも再確認。 |
Python Tracebackの読み方の順番
一番下の行を読む(Exception名とメッセージ)
まず最後の行の例外タイプとメッセージを読みます。
ここでエラーの方向性が分かります。
例えばJSONDecodeError: Expecting property name enclosed in double quotes
なら入力JSONの形式不正が疑われます。
ファイル名と行番号を特定する
次に、最後から2番目以降のフレーム(各File "...", line ..., in ...
の塊)のうち、自分のファイル名を探し、該当の行番号を確認します。
IDEやエディタではその行にジャンプできます。
例として、標準ライブラリjson
を使いつつ、自分のコード内で不正なJSONを渡す例です。
# example_json_error.py
# ライブラリ経由で例外が起きる典型例
import json
def load_user(json_text: str):
# 末尾の余計なカンマはJSONでは不正です
return json.loads(json_text)
def main():
bad = '{"id": 1, "name": "Alice", }' # ← 余計なカンマ
load_user(bad)
main()
Traceback (most recent call last):
File "example_json_error.py", line 12, in <module>
main()
File "example_json_error.py", line 10, in main
load_user(bad)
File "example_json_error.py", line 7, in load_user
return json.loads(json_text)
File "/usr/lib/python3.11/json/__init__.py", line 346, in loads
return _default_decoder.decode(s)
File "/usr/lib/python3.11/json/decoder.py", line 353, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/usr/lib/python3.11/json/decoder.py", line 369, in raw_decode
raise JSONDecodeError("Expecting property name enclosed in double quotes", s, err.value) from None
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 29 (char 28)
この場合、自分のコードの最後のフレームはFile "example_json_error.py", line 7, in load_user
で、ここでjson.loads
に不正な文字列を渡しているのが問題です。
呼び出し順を下からたどる
Tracebackは下に行くほど最新です。
下から上に向かって、自分の関数が何を呼び、その結果どうエラーに至ったかを追います。
必要に応じて各関数の入力値をprint
やlogging
で記録し、どこで不正な値が紛れ込んだかを突き止めます。
自分のコードとライブラリコードを見分ける
ファイルパスに自分のプロジェクトのパスが含まれているか、site-packagesやPythonの標準ライブラリのパスかで見分けます。
まずは自分のコードのフレームに集中し、それでも不明ならライブラリの呼び出し方や引数を見直します。
ライブラリ内部の深いフレームを延々と読むより、あなたのコードが何を渡したかに注目する方が速く解決します。
ケース別の見方のコツ
SyntaxErrorの矢印(^)と該当箇所の探し方
構文ミスは実行前に検出され、SyntaxError
やIndentationError
になります。
矢印^
はエラー近辺を示しますが、真犯人は一つ前のトークンであることがよくあります。
# example_syntax_error.py
# コンマの後に文字列をそのまま続けてしまった例
def greet(name):
print("Hello," name) # ← 本来は "Hello, " + name や f"Hello, {name}" と書く
File "example_syntax_error.py", line 4
print("Hello," name) # ← 本来は "Hello, " + name や f"Hello, {name}" と書く
^^^^
SyntaxError: invalid syntax
この場合、^
はname
側を指していますが、原因は","
の後に演算子がないことです。
次のように直せば動きます。
# 修正例
def greet(name):
print("Hello, " + name)
# または
print(f"Hello, {name}")
もう1つ、インデントの例です。
# example_indent_error.py
# インデントがずれている例
def add(a, b):
print(a + b) # ← ここはインデントが必要
File "example_indent_error.py", line 4
print(a + b) # ← ここはインデントが必要
^
IndentationError: expected an indented block
直前の行のコロン(:)を見落としていないか、スペースとタブが混ざっていないかも確認してください。
Import関連のエラーの読み方と確認ポイント
Importの失敗は主に2種類です。
# example_import_error.py
import request # ← 'requests' のタイポ。モジュールが存在しない
from math import sqroot # ← 'sqrt' のタイポ。モジュール内にその名前がない
Traceback (most recent call last):
File "example_import_error.py", line 3, in <module>
import request
ModuleNotFoundError: No module named 'request'
Traceback (most recent call last):
File "example_import_error.py", line 4, in <module>
from math import sqroot
ImportError: cannot import name 'sqroot' from 'math' (/usr/lib/python3.11/lib-dynload/math.cpython-311-x86_64-linux-gnu.so)
読み方と確認ポイントは次の通りです。
まずタイプで切り分け、次にモジュール名やシンボル名のスペルを確認します。
環境由来ならpython -m pip show パッケージ名
でインストール有無とバージョン、python -m pip install ...
で必要な環境に入っているかを確認します。
仮想環境の違いにも注意してください。
例外の連鎖を読む(“During handling of the above exception…” の意味)
例外処理中に別の例外を発生させると、Pythonは例外の連鎖として表示します。
2通りの文言があります。
- except中に新しい例外が起きた場合:
# example_chaining_during.py
def parse_int(text: str) -> int:
try:
return int(text)
except ValueError:
# ここで別の例外を新たに起こす
raise RuntimeError("数字への変換に失敗しました")
parse_int("abc")
Traceback (most recent call last):
File "example_chaining_during.py", line 5, in parse_int
return int(text)
ValueError: invalid literal for int() with base 10: 'abc'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "example_chaining_during.py", line 10, in <module>
parse_int("abc")
File "example_chaining_during.py", line 8, in parse_int
raise RuntimeError("数字への変換に失敗しました")
RuntimeError: 数字への変換に失敗しました
- 直接の原因を明示する
raise ... from e
を使った場合:
# example_chaining_direct.py
def parse_int(text: str) -> int:
try:
return int(text)
except ValueError as e:
# 直前の例外が直接の原因であることを明示
raise RuntimeError("数字への変換に失敗しました") from e
parse_int("abc")
Traceback (most recent call last):
File "example_chaining_direct.py", line 5, in parse_int
return int(text)
ValueError: invalid literal for int() with base 10: 'abc'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "example_chaining_direct.py", line 10, in <module>
parse_int("abc")
File "example_chaining_direct.py", line 8, in parse_int
raise RuntimeError("数字への変換に失敗しました") from e
RuntimeError: 数字への変換に失敗しました
「During handling…」はexcept中に起きた別の失敗、「direct cause」は因果関係を明示と覚えておくと読み解きやすいです。
長いTracebackで重要な行だけ拾うコツ
ライブラリが深く関与するとフレームが多くなります。
そんなときは以下を実践します。
まず一番下の例外タイプとメッセージを読む。
次に自分のファイルの最後のフレームを特定する。
そこで渡している引数と前提条件を点検する。
site-packagesや標準ライブラリ配下のフレームは一旦飛ばしても構いません。
どうしても追いたい場合は、上から1〜2フレームずつ読み、どの入力が不正化したのかを逆算します。
補助的に、例外を捕まえて短いスタックだけ印字する方法もあります。
# example_traceback_limit.py
# 長いスタックから末尾の数フレームだけを表示する例
import sys
import traceback
def f3():
return {}["missing"] # KeyError発生
def f2():
return f3()
def f1():
return f2()
try:
f1()
except Exception:
# 直近2フレームだけに制限してフォーマット
tb = traceback.TracebackException(*sys.exc_info(), limit=2)
print("".join(tb.format()))
Traceback (most recent call last):
File "example_traceback_limit.py", line 19, in <module>
f1()
File "example_traceback_limit.py", line 16, in f1
return f2()
KeyError: 'missing'
本番コードに恒常的に入れるのではなく、原因切り分けの一時的な補助として使うと便利です。
初心者向けの直し方チェックリスト
エラータイプと英文メッセージをそのまま検索
最後の行をそのままコピペして検索します。
例: "TypeError: 'NoneType' object is not iterable"
。
引用符ごと入れるとノイズが減ります。
英語のまま検索する方が解決例が見つかりやすいです。
必要に応じて公式ドキュメントや信頼できるQ&Aサイトを併用します。
該当行へジャンプして前後のコードを確認
Tracebackのファイル名と行番号に移動し、前後数行も含めて読みます。
値の素性を確かめるために、一時的にprint(repr(x))
やtype(x)
を仕込み、入力が想定通りか確認します。
Jupyterならセルの境界も意識し、どのセルで定義されたかを見直します。
最小の再現コードを作って原因を切り分け
関係ない部分を削っても同じエラーが再現する一番小さなコードを作ります。
これにより本質的な条件が浮き彫りになります。
# example_minimal_repro.py
# もとの大きな処理から、問題の本質だけを抽出した最小再現例
def normalize(items):
# itemsの中にNoneが混ざるとsumでTypeErrorになるという仮説を検証
return sum(items) / len(items)
# Noneを含む入力で本当に再現するか確認
print(normalize([1, None, 3]))
Traceback (most recent call last):
File "example_minimal_repro.py", line 9, in <module>
print(normalize([1, None, 3]))
File "example_minimal_repro.py", line 6, in normalize
return sum(items) / len(items)
TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
この例なら、None
を除外するか0に置き換えるなどの対策が考えられます。
同じTracebackを再現して修正を検証する
修正後は同じ操作でエラーが再現しないことを確認します。
再現手順をメモし、修正前後の振る舞いを比較してください。
可能なら簡単なテスト関数を用意し、意図的に不正値を与えても落ちないことを確認します。
エラーが消えただけでなく、正しい結果が得られているかも忘れずに確かめます。
まとめ
Tracebackはただのエラーログではなく、原因への道しるべです。
大切なのは一番下の例外タイプとメッセージから読み始めること、自分のコードの最後のフレームに注目すること、そして呼び出しを下から上へたどることです。
SyntaxErrorでは矢印の直前を、Importエラーではスペルと環境を、例外の連鎖では因果関係の表示に注目します。
長いTracebackでも慌てず、自分のファイルに関係する行だけを拾って原因を絞り込みましょう。
最後に、最小再現と修正の再検証を徹底することで、エラー対応は確実に上達します。
Tracebackを味方に、デバッグを効率化していきましょう。