Python の dict アクセスで KeyError が解消できない
KeyError は dict に存在しないキーを d[key] で参照したときに発生する。
事前チェックなら `if key in d`、デフォルト値を返すなら d.get(key, default)、欠落キーを許容したいなら collections.defaultdict を使い分ける。
スペース・改行・大文字小文字違いが原因のことも多い。
#dict#keyerror#exception#defaultdict
公開:
要約
KeyError は dict に存在しないキーを d[key] で参照したときに必ず発生する例外。
回避策は 3 つ: 事前に key in d で確認する、d.get(key, default) でデフォルト値を返す、collections.defaultdict で「キーが無ければ自動で空値を作る」運用にする。
例外メッセージにキー名がそのまま出るので、見えない空白や改行が混じっていないかも要確認。
よくある原因
- API レスポンスや JSON の構造が想定と違う。
OpenAPI でrequiredでないフィールドをd["foo"]で取りに行って落ちる。 - CSV ヘッダや環境変数の読み込み時に、末尾の改行や半角スペースが残ったままキーになっている。
- HTTP ヘッダや YAML の dict は大文字小文字の扱いが処理系で違う。
d["Content-Type"]とd["content-type"]は別キー。 - for ループの中で
d[f"item_{i}"]のようにキーを組み立てるとき、iの範囲が dict にない値まで含む。
解決策
1. d.get() を使う
value = d.get("name") # 無ければ None
value = d.get("name", "anon") # 無ければ "anon"公式ドキュメント の挙動どおり、例外を出さずに済む。
戻り値が None になり得る点に注意し、後段の属性アクセス前に is not None で絞ると安全。
2. in で先にチェックする
if "name" in d:
print(d["name"])「キーがあるときだけ何かする」明示的なフローを書きたい場合はこちら。
3. defaultdict で初期値を任せる
from collections import defaultdict
counts = defaultdict(int)
for word in words:
counts[word] += 1 # 初出キーは 0 から開始リスト追加なら defaultdict(list)、ネスト dict なら defaultdict(dict) を使う。
挙動の詳細は collections 公式ドキュメント を参照。
4. キー文字列を正規化する
clean = {k.strip().lower(): v for k, v in raw.items()}
clean["content-type"]CSV / 環境変数 / HTTP ヘッダから dict を作るときは、読み込み直後に空白除去と小文字化をしておくと「見えないバグ」を予防できる。