できない.dev

Python の dict アクセスで KeyError が解消できない

KeyError は dict に存在しないキーを d[key] で参照したときに発生する。
事前チェックなら `if key in d`、デフォルト値を返すなら d.get(key, default)、欠落キーを許容したいなら collections.defaultdict を使い分ける。
スペース・改行・大文字小文字違いが原因のことも多い。

公開:

要約

KeyError は dict に存在しないキーを d[key] で参照したときに必ず発生する例外。
回避策は 3 つ: 事前に key in d で確認する、d.get(key, default) でデフォルト値を返す、collections.defaultdict で「キーが無ければ自動で空値を作る」運用にする。
例外メッセージにキー名がそのまま出るので、見えない空白や改行が混じっていないかも要確認。

よくある原因

  1. API レスポンスや JSON の構造が想定と違う。
    OpenAPI で required でないフィールドを d["foo"] で取りに行って落ちる。
  2. CSV ヘッダや環境変数の読み込み時に、末尾の改行や半角スペースが残ったままキーになっている。
  3. HTTP ヘッダや YAML の dict は大文字小文字の扱いが処理系で違う。d["Content-Type"]d["content-type"] は別キー。
  4. 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 を作るときは、読み込み直後に空白除去と小文字化をしておくと「見えないバグ」を予防できる。

実行例

実際に上記の手順を python:3.12(Debian GNU/Linux 13 trixie)環境で動かすと、d["email"] へのアクセスで KeyError: 'email' が発生し(終了コード 1)、続いて d.get()in チェック・defaultdict の 3 つの解消策がいずれも正常に動作することを確認できる。

== versions ==
PRETTY_NAME="Debian GNU/Linux 13 (trixie)"
Python 3.12.13
git version 2.47.3
== run ==
--- python bad.py (KeyError: "email" を想定)---
Traceback (most recent call last):
  File "/tmp/tmp.9cAOvd641l/bad.py", line 2, in <module>
    print(d["email"])
          ~^^^^^^^^^
KeyError: 'email'
終了コード: 1
--- 解消1: d.get() でデフォルト値を返す ---
get なし既定 : None
get 既定指定 : no-email@example.com
--- 解消2: in でキー存在を先に確認する ---
name = alice
email は dict に無い
--- 解消3: collections.defaultdict で自動初期化 ---
{'apple': 3, 'banana': 2, 'cherry': 1}

— 2026-07-01 時点の出力

この記事は役立ちましたか?