この記事の目的と読むべき人
このドキュメントは、以下のような人向けです。
- Pythonの学習を始めたばかりで、エラーメッセージを素早く理解したい人
- 日常的なデバッグの効率を上げたいエンジニア、学生
- レビューや教育でエラーの原因を説明する必要がある人
定義(1行):エラーとは、Python実行時または構文解析時に発生してプログラムの継続を妨げる例外や問題です。
重要: 実際の開発では、エラーメッセージを最初から最後までよく読むことが最も重要です。エラートレース(traceback)は多くの手がかりを与えます。
目次
- IndentationError(インデントエラー)
- SyntaxError(構文エラー)
- IndexError(インデックスエラー)
- ValueError(値エラー)
- AttributeError(属性エラー)
- よくある原因と総合的なデバッグ手順
- ロール別チェックリスト
- 決定フロー(簡易マップ)
- 受け入れ基準・テストケース
- 1行用語集
- まとめ
IndentationError
Pythonにおけるブロック(条件分岐、関数、ループなど)は波括弧ではなくインデント(字下げ)で表現します。ブロック内部のすべての文は同じインデントレベルである必要があり、ずれがあるとIndentationErrorが発生します。
よくある原因:
- コードを別のエディタにコピー&ペーストした際に空白とタブが混在する
- インデントの深さ(スペースの数)が揃っていない
- 期待されるブロック開始時にコロン(:)を忘れるためインデントが不正になる
例:
for i in range(5):
print(i)
修正例:
for i in range(5):
print(i)
対処手順:
- エラーメッセージの行番号を確認する。
- その周辺のインデントをすべて目視で揃える。
- エディタの「タブ表示」機能で空白とタブを可視化する。
- プロジェクトのコードスタイルに合わせて「タブをスペースに変換」またはその逆を行う。
- 自動整形ツール(black、autopep8等)を導入する。
予防策:
- エディタ設定で「タブをスペースに変換」を有効にする(PEP8では4スペース推奨)。
- Linter(flake8, pylint)をCIに組み込む。
適用できない状況の例(反例):
- インデントそのものが正しく、実はコロン(:)が抜けていた場合。エラーメッセージは似ているが原因は異なる。
SyntaxError
SyntaxErrorは、コードがPythonの構文規則に従っていないときに発生します。プログラムは実行開始前に解析され、この段階で構文的なミスがあると実行できません。
よくある原因:
- コロン(:)やカンマ(,)の欠如
- 括弧、角括弧、ブラケットの未閉鎖
- 文字列の終端引用符の欠如
- キーワードのつづり間違い(例: esle など)
- 文法的に無効な構造(例: 文の順序や位置が不正)
例:
- 条件や関数の定義で「:」を忘れる
- 閉じ括弧が足りない
対処手順:
- エラーメッセージの行番号と位置を確認する(>>や^で示されることが多い)。
- その行の前後(特に前の行)も必ずチェックする。多くの場合、実際の原因は前行にある。
- 括弧やクォートが正しく閉じられているか確認する。
- オンラインの構文ハイライトやIDEのインスペクションを利用する。
予防策:
- 静的解析ツールやフォーマッタを導入する。
- Gitのコミット前にpre-commitで構文チェックを行う。
反例:
- 実行時に起きる例外(ValueErrorやAttributeErrorなど)はSyntaxErrorとは別問題なので、切り分けが必要。
IndexError
IndexErrorはリストやタプル、文字列などのシーケンスに対して、範囲外のインデックスでアクセスしたときに発生します。Pythonのインデックスは0始まりである点をよく忘れがちです。
例:
numbers = [1, 2, 3]
print(numbers[1]) # 2 を表示
print(numbers[3]) # IndexError: list index out of range
よくある原因:
- ループ内でシーケンスを変更(削除・挿入)している
- オフバイワン(+/-1のズレ)
- 空のリストにアクセスしている
対処手順:
- len()で長さを確認する。
- 範囲チェックを行う(if 0 <= index < len(seq))。
- enumerateやforループで直接要素を扱う(インデックスを使わない方法)に切り替える。
例(安全なアクセス):
index = 3
if index < len(numbers):
value = numbers[index]
else:
value = None # またはエラーハンドリング
反例/注意点:
- negative index(-1で最後の要素など)が使われている場合、それ自体は有効だが範囲外になることもある。必ずlen()と組み合わせて検証する。
ValueError
ValueErrorは、関数や演算が受け取る値が型としては正しいが、その値が意味的に不正な場合に発生します。たとえば数値変換や数学関数のドメイン違反など。
例:
int('10') # OK -> 10
int('ten') # ValueError
import math
math.sqrt(-5) # ValueError(数学的に定義されない)
よくある原因:
- ユーザー入力が期待する形式になっていない
- ファイルや外部APIから受け取ったデータが不正
- 関数の引数に意味的に不正な値を渡した
対処手順:
- try-exceptでValueErrorをキャッチして、ユーザーに再入力を促すや、デフォルト値を代入する。
try:
num = input("数値を入力してください: ")
num_int = int(num)
except ValueError as e:
print(f"ValueErrorを検出: {e}")
# 再入力、ログ、デフォルト代入など
- 入力検証関数を作る(正規表現やパーサーを利用)。
- 数学的関数には事前条件チェック(引数が正の数であるか等)を入れる。
予防策:
- 受け取るデータの契約(型と意味)を明確にし、ドキュメント化する。
- バリデーション層を設ける(API→バリデータ→ロジック)。
AttributeError
AttributeErrorは、オブジェクトに存在しない属性(プロパティやメソッド)にアクセスしようとしたときに発生します。型が期待と異なるときに起きる代表的な例です。
例:
text = "hello world"
print(text.push()) # AttributeError: 'str' object has no attribute 'push'
user = None
print(user.name) # AttributeError: 'NoneType' object has no attribute 'name'
対処手順:
- type(obj) や isinstance() で型を確認する。
- dir(obj) で利用可能な属性一覧を確認する。
- Noneチェックを入れる(if obj is not None: …)。
- 属性があるかどうかを安全に確認する場合は getattr(obj, ‘attr’, default) を使う。
例(安全な属性参照):
if hasattr(user, 'name'):
print(user.name)
else:
print('name属性が存在しません')
予防策:
- 型注釈(type hints)を使ってIDEに支援させる。
- テストで各オブジェクトのインターフェースを検証する(ユニットテスト)。
よくある原因と総合的なデバッグ手順
共通のデバッグ手順(ミニ・メソドロジー):
- エラーメッセージとスタックトレースを最初から最後まで読む。
- エラー発生箇所とその直前の数行を確認する。
- 型や値をprint/ログで出力して期待値と比較する。
- 変更点(Gitのdiffや最近のコミット)を確認する。
- 小さな再現コード(最小事例)を作る。
- 修正後はユニットテストと手動の回帰テストを行う。
Fact box(キーポイント):
- インデントはスペース4つが標準(PEP8)。
- Pythonのインデックスは0始まり。
- ValueErrorは型は合っているが値が不正な場合に発生。
- AttributeErrorはそのオブジェクトが属性を持っていないときに発生。
ロール別チェックリスト
開発者:
- Linterとformatterを設定してコミット前に自動実行する。
- 例外を無闇に握りつぶさない(empty except を避ける)。
コードレビュワー:
- インデントや演算子の使い方、境界条件のテストがあるか確認する。
- Noneチェックやタイプの保証が適切か確認する。
QA / テスター:
- 境界値(空配列、最大インデックス、負の数、無効な文字列など)を含むテストケースを準備する。
- 不正入力に対する振る舞い(エラーメッセージ、HTTPステータス等)を検証する。
決定フロー(簡易マップ)
以下はエラー種別を切り分ける簡易フローチャートです。問題の最初の一歩が何かを素早く見つける助けになります。
flowchart TD
A[プログラムが動かない/例外が出る] --> B{エラーメッセージはSyntaxErrorか?}
B -- はい --> C[構文を確認: 括弧・クォート・コロン]
B -- いいえ --> D{実行時例外か?}
D -- はい --> E[スタックトレースの最下層の行を確認]
E --> F{AttributeError?}
F -- はい --> G[型チェック・dir''・hasattr''を実行]
F -- いいえ --> H{IndexError?}
H -- はい --> I[len''や範囲チェックを適用]
H -- いいえ --> J{ValueError?}
J -- はい --> K[入力のバリデーション・try/exceptで処理]
J -- いいえ --> L[ログを増やして再現コードを作成]
受け入れ基準とテストケース(簡易)
受け入れ基準:
- エラーが発生する箇所に対して明確な原因と修正案が書かれている。
- 修正後に自動テストが通る。
- 入力に対する境界値テストが存在する。
テストケース例:
- 空リストへアクセスしたときに期待する例外または安全な動作を返す。
- int()による変換が失敗する文言を適切にハンドルする。
- Noneを想定したオブジェクト参照でAttributeErrorを返さない。
よくある修正パターン(チートシート)
- IndentationError: エディタで「表示: タブ/スペース」を有効にして揃える。autopep8/blackを適用。
- SyntaxError: 該当行だけでなく前行も確認。クォートと括弧の閉じ忘れに注意。
- IndexError: len()チェック、enumerateを活用。イテレーション中のシーケンス変更を避ける。
- ValueError: 入力バリデータ、try/except、事前条件チェックを追加。
- AttributeError: isinstanceチェック、hasattr/getattr を使って安全に扱う。
1行用語集
- トレースバック: 例外発生時の呼び出し履歴。
- Linter: コード品質やスタイルの問題を指摘するツール。
- Formatter: コード整形ツール(例: black)。
- オフバイワン: 境界条件で+/-1のミス。
ロールプレイブック(短いSOP)
短時間でエラーを解決するための手順:
- 再現手順を明確化する(最小再現コードを作る)。
- エラーメッセージとトレースバックを保存する(ログ)。
- 仮説を立てて最小限のprint/ログで検証する。
- 修正を加え、ユニットテストを追加する。
- レビューを経てマージし、リリース後に監視する。
ローカル環境固有の注意点(日本の開発現場向け)
- エディタのデフォルトタブ幅が異なるとチーム内で混乱しやすい。チームの共通設定(.editorconfig)を採用する。
- 全角スペースの混入は見落としやすく、IndentationErrorの原因になるので注意。
まとめ
- Pythonでよく見るエラーは、原因の切り分けと最小再現コード作成で素早く解決できる。
- 自動整形ツール、静的解析、バリデーションの導入で多くの問題は未然に防げる。
- エラー発生時はメッセージを読み、型・値・構文のどれが問題かを順序立てて確認すること。
extras:
- 継続的学習のヒント: エラーに当たったら、そのエラー名で検索して他人の事例を読むと学びが早い。