Menu
日本語
Playgroundで試す

Pythonエラー種類別の原因と対処法|トレースバックの読み方

KeyError、ValueError、ModuleNotFoundError、EOFError など、Pythonでよく遭遇するエラーの原因と直し方を、トレースバックの読み方とあわせて整理しました。

エラーは Python からのメッセージ

Python のエラーは、型・メッセージ・トレースバック(そこに至るまでの呼び出しの連鎖)を持つオブジェクトです。これをきちんと読めるようになることが、デバッグ力を伸ばすいちばんの近道だったりします。このページでは、実際によく遭遇するエラーの種類と、素早く直すための習慣をまとめて紹介します。

try/except の仕組みや自作例外の raise については、例外処理のページで文法を解説しています。このページでは、具体的なエラーとトレースバックの読み方にフォーカスします。

トレースバックの読み方

わざとエラーを起こしてみましょう。

def divide(a, b):
    return a / b

def report(values):
    for v in values:
        print(divide(10, v))

report([5, 2, 0])

Pythonは次のような内容を出力します。

Traceback (most recent call last):
  File "script.py", line 8, in <module>
    report([5, 2, 0])
  File "script.py", line 6, in report
    print(divide(10, v))
  File "script.py", line 2, in divide
    return a / b
ZeroDivisionError: division by zero

下から上に向かって読んでいきます:

  1. ZeroDivisionError: division by zero — 例外の種類とメッセージ。これが 何が起きたか を示しています。
  2. divide 関数の2行目、return a / b — 実際に例外が発生した行。
  3. report 関数の6行目、print(divide(10, v)) — エラーの引き金となった呼び出し。
  4. モジュールレベルの8行目、report([5, 2, 0]) — すべての始まり。

修正すべき箇所は、たいていトレースバックの一番下のフレームにあります。ただし、ライブラリの奥深くでエラーが発生している場合は、トレースバックを上にたどって 自分のコード に現れる最初のフレームを探しましょう。そこが、不正な値を渡している呼び出し元です。

よく遭遇するエラーの種類

NameError

main.py
Output
Click Run to see the output here.

「Name 'mesage' is not defined.」というやつですね。タイポや、まだ代入していない変数を使ってしまったときに出るエラーです。最近のバージョンのPythonなら、近い名前を提案してくれることが多いです(「Did you mean 'message'?」のように)。

対処法としては、まずスペルとスコープを確認しましょう。関数の中でしか定義されていない変数は、関数の外からは参照できません。

TypeError

main.py
Output
Click Run to see the output here.

「can only concatenate str (not 'int') to str」。要するに、その操作にその型は使えないよ、というエラーです。定番パターンは、文字列と数値を足そうとする、呼び出せないものを呼び出す、関数に渡す引数の数が合っていない、あたり。

対処法としては、str(30)int("30") のように型を明示的に変換するか、自分が実際に何を渡しているのかを確認しましょう。型をまたいで + で連結するより、f文字列を使ったほうが読みやすくなることが多いです: f"age: {30}"

ValueError

main.py
Output
Click Run to see the output here.

「Invalid literal for int() with base 10: 'hello'」というやつですね。型自体は合っていて、int() は文字列を受け取れるのですが、がダメというパターンです。int()float()、日時のパース、引数に範囲制限があるような関数でよく遭遇します。

対処法は、変換する前にバリデーションをかけるか、エラーをキャッチしてハンドリングするかのどちらかです:

main.py
Output
Click Run to see the output here.

KeyError

main.py
Output
Click Run to see the output here.

KeyError: 'charlie'」は、指定したキーが辞書に存在しないときに出るエラーです。対処のしかたは、何をしたいかによって3通りの書き方が定番です。

main.py
Output
Click Run to see the output here.

キーが無いときに自動で初期化してほしい辞書なら、collections.defaultdict を検討してみてください。

IndexError

main.py
Output
Click Run to see the output here.

「List index out of range」は、存在しない位置を指定したときに出るエラーです。

対処法としては、長さをチェックしてからアクセスする、最後の要素を取りたいなら -1 を使う、あるいはスライス(numbers[5:6] なら例外ではなく [] が返ってくる)を活用するのがおすすめです。

AttributeError

main.py
Output
Click Run to see the output here.

'NoneType' object has no attribute 'upper'」。存在しないメソッドを呼び出したときに出るエラーです。ほぼ間違いなく、変数の型が想定と違う(多くの場合、値が入っているはずなのに None になっている)ケースです。

対処法は、その None がどこから来たのかを突き止めること。エラーが出る直前に print(type(var)) を仕込むか、ブレークポイントを置くのが一番早いです。「失敗することがある関数」は大抵失敗時に None を返すので、戻り値を受け取ったらメソッドを呼ぶ前に必ずチェックしましょう。

ModuleNotFoundError(および ImportError)

import fastapi

No module named 'fastapi'」と出るのは、スクリプトが使っている Python インタプリタにそのパッケージが入っていないということです。よくある原因は次の 2 つ。

  1. 本当にインストールしていないパターン。正しい環境で python -m pip install fastapi を実行しましょう。
  2. インストールはしたけど、別の Python に入れてしまったパターン。macOS だと pippython が別々のインストール先を指していることがよくあり、これが頻発します。

確実な解決策は、実行に使うインタプリタと同じもので入れること:

python -m pip install fastapi

仮想環境を使っているなら(使うべきですが)、pip installpython script.py のどちらを実行するときも、ちゃんと仮想環境がアクティブになっているか確認しましょう。

FileNotFoundError

with open("settings.yaml") as f:
    config = f.read()

「[Errno 2] No such file or directory: 'settings.yaml'.」というやつですね。スクリプトを実行している場所から見て、そのパスが存在していないというエラーです。

対処法としては、まずスクリプトの先頭で os.getcwd() を出力して、Python がどこを基準にファイルを探しているのか確認しましょう。あとは絶対パスを使うか、pathlib.Path(__file__).parent / "settings.yaml" のように書いて、スクリプト自身の場所を基準にパスを組み立てるのがおすすめです。

EOFError

name = input("Name: ")

「EOF when reading a line」というエラーは、input() が標準入力から読もうとしたのに何もなかったときに出ます。空のソースからパイプで流し込まれたか、プロンプトで Ctrl-D を押してしまったかのどちらかです。

対処法: パイプからの入力が正当なケースなら、次のように囲んでおきましょう:

try:
    name = input("Name: ")
except EOFError:
    name = "anonymous"

ブラウザ上のエディタでは実行環境が入力をシミュレートするため、このエラーに遭遇することはありません。

IndentationErrorSyntaxError

IndentationError: expected an indented block after function definition on line 2

これらは特別で、プログラムが実行されるに発生します。Python がファイルをパースできずに拒否した状態です。

  • IndentationErrordefiffor などの本体がなかったり、インデントがズレていたりするときに出ます。最近のエディタはインデントを可視化してくれるので、「空白文字を表示」をオンにしておくと、タブとスペースの混在が見つけやすくなります。
  • SyntaxError — コロンの付け忘れ、括弧の対応ミス、キーワードのスペルミスなどが原因です。最近のバージョンの Python なら、問題の文字を矢印(^)で指し示してくれます。

対処法: エラーメッセージに行番号が出ているので、まずそこを見に行きましょう。その行に明らかな問題が見当たらないときは、その1つ上の行も疑ってみてください。数行前で閉じ忘れた括弧が、ずっと後ろの行の構文エラーとして報告されることはよくあります。

RuntimeError

「実行時に何か問題が起きたけど、もっと具体的なエラーには当てはまらない」という、いわば何でも屋のエラーです。再帰の深さを超えたときに出る RecursionError はその代表例。ライブラリのコードでも、内部状態がおかしくなったときに RuntimeError が投げられることがよくあります。

対処法: メッセージをよく読みましょう。たいてい内容が具体的に書かれています。再帰が原因なら、ループに書き換えるのが基本。どうしても必要な場面に限り、sys.setrecursionlimit で上限を引き上げるという手もあります。

本格的なデバッガを使う前に、まずは print() ——さらに便利なのは f"{var=}" の書き方——で大抵のバグは捕まえられます:

main.py
Output
Click Run to see the output here.

f"{var=}" と書くと、式のソースと値をまとめて表示してくれるので、フォーマット文字列の中で変数名をもう一度打ち直す必要がありません。スクリプトを実行し、出力をざっと眺めて、値がおかしくなった行を探す。「謎のバグ」と思っていたものも、要所に3〜4個 print を仕込むだけであっさり原因が見えてくることがほとんどです。

コミット前には print デバッグのコードを片付けておきましょう。本番に投入するコードには、print よりも logging.debug(...) の方がおすすめです。行をいちいち編集しなくても、デバッグ出力のオン・オフを切り替えられます。

breakpoint() と pdb の使い方

print デバッグでは手が届かない場面では、breakpoint() を書いておくと、その地点で Python 標準の対話型デバッガが立ち上がります。

def discount(price, percent):
    breakpoint()
    return price * (1 - percent / 100)

discount(100, 20)

スクリプトは必ず実ターミナルで実行してください。起動すると (Pdb) プロンプトに入ります。覚えておきたいコマンドはこのあたり:

  • p variable — 変数の中身を表示。
  • n — 次の行へ進む。
  • s — 関数の中へステップイン。
  • c — 次のブレークポイントか終了まで一気に実行。
  • q — 終了。
  • l — 現在行付近のソースを表示。

VS Code や PyCharm といったIDEのデバッガも、同じプロトコルをGUIで包んだものです。行番号のところをクリックしてブレークポイントを置いたり、サイドバーで変数を眺めたり。自分にとって面倒が少ないほうを選べばOKです。

エラーを減らすための習慣

  • 変数名はきちんと説明的に書く。 TypeErrorAttributeError の半分くらいは、「この変数に何が入っているか忘れない名前」にしておくだけで消えます。
  • 入力は境界でバリデーションする。 ユーザー入力やファイルの内容は、関数の入口で一度だけパース・チェックする。そうすれば、それ以降のコードは値を信用して書けます。
  • 黙って握りつぶさない、派手に落とす。 except Exception: pass は、本当に見るべきエラーまで隠してしまいます。例外は具体的に捕まえて、意図を持って処理し、それ以外は素直に上に投げましょう。
  • トレースバックはまず一番下から読む。 トレースバックの読み方を身につける時間は、100倍になって返ってきます。

ほとんどのエラーはミステリーじゃありません。たいていは1行のタイポか、型の取り違えで、メッセージもちゃんと書いてあります。エラーメッセージを信じてください。だいたい合っています。

ここまでお疲れさまでした

リファレンスパートはここで一区切りです。「そもそもPythonって?」から始まって、変数、制御フロー、コレクション、関数、クラス、イテレーション、実データの扱い、そしてエラーまで一通り駆け抜けてきました。ここから先は、プロジェクト単位で進めるフェーズです。作りたいものを一つ決めて、必要なピースを逆算しながら深掘りしていきましょう。具体的な疑問にぶつかったとき、このページはいつでもここで待っています。

よくある質問

PythonのKeyErrorはどんなときに出ますか?

KeyErrorは、辞書に存在しないキーを参照したときに発生します。たとえばusers["missing"]とするとKeyError: 'missing'になります。安全に書くなら、デフォルト値を渡すusers.get("missing", default)、Noneでよければusers.get("missing")、あるいはif key in users:で事前にチェックする書き方がおすすめです。

EOFErrorは何が原因で出るのですか?

EOFError(end-of-file)は、input()が何も読み取れずに入力ストリームが閉じてしまったときに発生します。よくあるのは、input()を使うスクリプトにデータなしでパイプした場合や、対話プロンプトで Ctrl-D を押してしまった場合です。パイプ入力を想定するスクリプトなら、try/except EOFErrorで明示的にハンドリングしておくと安全です。

ModuleNotFoundErrorが出たらどう直す?

ModuleNotFoundErrorは、import XXという名前のモジュールが見つからなかったという意味です。原因は大きく2つで、パッケージ自体が入っていない(pip install Xで解決)か、実行中のPythonとは別のPythonにインストールされているケース(複数のPythonが入っている環境でよくある落とし穴)です。後者はpython -m pip install Xのように、実行中のインタプリタ経由でインストールすれば直ります。

Pythonのトレースバックはどう読めばいいですか?

基本は下から上に読みます。一番下の行が例外の種類とメッセージで、実際に何が起きたのかを示しています。その上の行は、そこに至るまでの呼び出し履歴(コールスタック)で、自分が書いたコードは下の方に出てくることが多いです。まずは一番下にある自分のファイル名と行番号に飛んで、そこを直すのが最短ルートです。

Coddyでコードを学ぼう

始める