3秒でわかる
Python でリストの範囲外を指したときに出る例外。件数と添字のずれを知らせる合図なので、境界の条件を見直す手がかりになります。
もう少し詳しく
どういうものか
IndexError は、リストやタプルなどの順序を持つデータに対して、存在しない位置を指定したときに送出される Python の例外です。要素が 3 個のリストで lst[3] を読もうとすると発生します。
添字は 0 から始まるため、要素が n 個なら使えるのは 0 から n-1 までです。この 1 つのずれが原因の大半を占めます。
なぜ必要か
黙って隣の値を返されるより、その場で止まるほうが安全です。C 言語のように範囲を確認しない言語では、範囲外の読み書きが別の変数の領域を壊し、まったく無関係な場所で異常が出ます。Python は毎回範囲を確認しているため、間違えた行そのものが指摘されます。
具体例
items = ["a", "b", "c"]
print(items[2]) # c 最後の要素
print(items[3]) # IndexError: list index out of range
print(items[-1]) # c 末尾から数える書き方は範囲内エラー表示は次のように出ます。
Traceback (most recent call last):
File "app.py", line 5, in <module>
print(items[3])
IndexError: list index out of range安全に扱うなら、添字を自分で作らず要素を直接回します。
for item in items:
print(item)
# 番号も欲しいときは enumerate を使う
for i, item in enumerate(items):
print(i, item)つまずきやすいところ
range(len(items) + 1) のように上限を 1 つ足してしまう書き方が典型例です。range(3) は 0、1、2 を返すので、range(len(items)) で過不足がありません。
ループの中で remove や pop を使い、回している最中に長さを変えるのも危険です。途中で要素が減り、後半で範囲外になります。削除するなら新しいリストを作り直すほうが安全です。
外部データを扱うときは特に注意が要ります。CSV の 1 行を split(",") で分けて 5 列目を読む処理は、列が欠けた行が 1 つあるだけで落ちます。件数を確認してから読むか、try で捕まえて行番号とともに記録します。
似た用語との違い
| 例外 | 起きる状況 |
|---|---|
| IndexError | リストの範囲外を指した |
| KeyError | 辞書に無いキーを指した |
| TypeError | 型が合わない操作をした |
| ValueError | 型は合うが値が不正 |
覚え方
「最後の番号は件数マイナス 1」。ここだけ押さえれば大半は防げます。