辞書(dict)は、キーと値のペアでデータを持つ、Pythonの基本的なデータ構造です。リストが「順番(位置)」で値を取り出すのに対し、辞書は「名前(キー)」で値を取り出します。{"name": "山田", "age": 30}のように波かっこで書きます。
もっともつまずきやすいのは、存在しないキーを[]で取り出そうとするとKeyErrorでプログラムが止まることです。これを避けるgetの使い方が、辞書を安全に扱うカギになります。この記事では、実機のPythonで確認しながら、辞書の使い方を整理します。
- 作成は
{"name": "山田", "age": 30}、空は{}です。 - 取り出しは
d["name"]。存在しないキーはKeyErrorになります。 - 安全に取り出すなら
d.get("key")(無ければNone)、既定値はd.get("key", 既定)です。 - 追加・更新はどちらも
d["key"] = 値。まとめて足すならd.update({...})です。 - ループは
for key, value in d.items():。辞書は追加した順番を保ちます(Python 3.7以降)。 "key" in dはキーの存在を調べます(値ではありません)。
もう1つの基本データ構造であるリストはリスト(list)の使い方、辞書のループに使う繰り返しはforループで繰り返し処理を行う方法、連番作成はrange関数の使い方もあわせて参考になります。
辞書を作る
辞書は波かっこ{ }でキーと値を:でつないで書きます。dict()関数でも作れます。
# キー: 値 のペアで作る
user = {"name": "山田", "age": 30, "city": "東京"}
# 空の辞書
config = {}
# dict() でも作れる
user2 = dict(name="佐藤", age=25)
# ペアのリストから作る
pairs = dict([("a", 1), ("b", 2)]) # {'a': 1, 'b': 2}
# キーは文字列以外(数値など)も使える
scores = {1: "金", 2: "銀", 3: "銅"}
キーには文字列だけでなく、数値なども使えます。値には何でも入れられます(リストや別の辞書も可能です)。
値を取り出す([] と get)
値はキーを指定して取り出します。方法は2つあり、d["key"]とd.get("key")です。違いはキーが存在しないときの挙動です。
user = {"name": "山田", "age": 30}
# [] で取り出す
user["name"] # 山田
user["age"] # 30
# get で取り出す(存在しなくてもエラーにならない)
user.get("name") # 山田
user.get("xxx") # None(存在しないキー)
user.get("xxx", "不明") # 不明(既定値を指定できる)
【重要】存在しないキーはKeyError
ここが最大の注意点です。d["存在しないキー"]と書くと、KeyErrorという例外が発生してプログラムが止まります。一方、d.get("存在しないキー")はNoneを返すだけで止まりません。
user = {"name": "山田"}
# NG: 存在しないキーを [] で取り出すと KeyError で止まる
# print(user["age"]) # KeyError: 'age'
# OK: get なら安全(無ければ None)
print(user.get("age")) # None
print(user.get("age", 0)) # 0(既定値を返す)
# キーがあるか確認してから [] で取り出す方法もある
if "age" in user:
print(user["age"])
実機で確認したところ、辞書に無いキーをuser["xxx"]で取り出すとKeyErrorになり、user.get("xxx")はNone、user.get("xxx", "不明")は"不明"を返しました。JSONやフォームから受け取ったデータなど、キーがあるか分からないときはgetを使うのが安全です。確実にキーがある場合や、無いことがバグだと知らせたい場合は、あえて[]を使う、と使い分けます。
追加・更新する
値の追加と更新は、どちらもd["key"] = 値で行います。キーが無ければ追加、あれば更新です。複数をまとめて反映するならupdateを使います。
d = {"a": 1}
# 追加(キーが無いとき)
d["b"] = 2 # {'a': 1, 'b': 2}
# 更新(キーがあるとき)
d["a"] = 99 # {'a': 99, 'b': 2}
# まとめて追加・更新
d.update({"c": 3, "a": 100}) # {'a': 100, 'b': 2, 'c': 3}
# 2つの辞書を結合する(Python 3.9 以降)
merged = {"x": 1} | {"y": 2} # {'x': 1, 'y': 2}
実機でも、d["a"] = 99で既存キーが更新され、updateでまとめて反映できました。追加と更新が同じ書き方なので、「無ければ作る、あれば上書き」を意識せずに書けます。
削除する(del / pop)
削除はdelまたはpopを使います。popは削除した値を返し、既定値を指定すれば存在しないキーでも安全です。
d = {"a": 1, "b": 2, "c": 3}
# キーで削除
del d["a"] # {'b': 2, 'c': 3}
# 削除して値を受け取る
value = d.pop("b") # value=2, d={'c': 3}
# 存在しないキーは del も pop もエラーになる
# del d["zzz"] # KeyError
# pop は既定値を指定すれば安全
safe = d.pop("zzz", None) # None(エラーにならない)
# すべて削除
d.clear() # {}
実機でも、del d["a"]でキーを削除でき、d.pop("b")は削除した値2を返しました。popに既定値を渡すと、存在しないキーでもエラーにならず既定値が返ります。delと既定値なしのpopは、存在しないキーでKeyErrorになる点に注意してください。
ループ処理する(keys / values / items)
辞書をループするには3つの方法があります。キーだけ、値だけ、キーと値の両方です。実務でいちばん使うのはitems()です。
user = {"name": "山田", "age": 30, "city": "東京"}
# キーでループ(そのまま for で回すとキー)
for key in user:
print(key) # name, age, city
# 値でループ
for value in user.values():
print(value) # 山田, 30, 東京
# キーと値の両方(最もよく使う)
for key, value in user.items():
print(key, value) # name 山田 / age 30 / city 東京
実機でも、辞書をそのままforで回すとキーが取れ、items()でキーと値を同時に取り出せました。Python 3.7以降、辞書は追加した順番を保つため、ループでも書いた順に出てきます。古い情報では「辞書は順序を保証しない」とされていますが、現在のPythonでは順序が保たれます。
キーの存在確認(in はキーを見る)
あるキーが辞書にあるかはinで調べます。注意点は、inが調べるのは「キー」であって「値」ではないことです。
user = {"name": "山田", "age": 30}
"name" in user # True(キーがある)
"xxx" in user # False
"name" not in user # False
# 注意: in はキューを見る。値では False になる
"山田" in user # False("山田" は値であってキーではない)
# 値で探したいときは values() を見る
"山田" in user.values() # True
len(user) # 2(ペアの数)
実機でも、"name" in userはTrue、値である"山田"をin userで調べるとFalseになりました。値が含まれるか調べたいときはin user.values()を使います。「キーで判定しているのか、値で判定しているのか」を意識してください。
出現回数を数える(get / setdefault)
辞書がもっとも活きるのが集計です。「キーごとの回数」を数えるときはget、「キーごとにリストへ振り分ける」ときはsetdefaultが便利です。
# 出現回数を数える(get で「無ければ0」から +1)
words = ["a", "b", "a", "c", "a", "b"]
counts = {}
for w in words:
counts[w] = counts.get(w, 0) + 1
print(counts) # {'a': 3, 'b': 2, 'c': 1}
# キーごとにリストへ振り分ける(setdefault で「無ければ空リスト」)
members = [("A", "赤"), ("B", "青"), ("C", "赤")]
groups = {}
for name, team in members:
groups.setdefault(team, []).append(name)
print(groups) # {'赤': ['A', 'C'], '青': ['B']}
実機でも、counts.get(w, 0) + 1で出現回数が{'a': 3, 'b': 2, 'c': 1}と数えられ、setdefault(team, []).append(name)でチームごとにメンバーを振り分けられました。setdefault("key", 既定)は「キーがあればその値、無ければ既定値を設定して返す」働きをします。より高度な集計には、標準ライブラリのcollections.Counterやdefaultdictも便利です。
キーは変更できない値だけ
辞書のキーには、文字列・数値・タプルなど変更できない(不変な)値しか使えません。リストのような変更できる値はキーにできず、使おうとするとTypeErrorになります。
# OK: 文字列・数値・タプルはキーにできる
d = {"a": 1, 10: "x", (1, 2): "座標"}
# NG: リストはキーにできない(変更できる値だから)
# bad = {[1, 2]: "x"} # TypeError: unhashable type: 'list'
# 値には何でも入れられる(リストや辞書もOK)
data = {"items": [1, 2, 3], "meta": {"count": 3}}
実機でも、リストをキーにしようとするとTypeError: unhashable type: 'list'になりました。一方、値には何でも入れられます(リストや別の辞書も可能です)。「キーは固定の名前、値は自由」と覚えておくとよいでしょう。
よくある失敗
存在しないキーを[]で取り出してKeyError
キーがあるか分からないときはd.get("key")(無ければNone)かd.get("key", 既定値)を使います。
inで値を探そうとする
inはキーを調べます。値が含まれるか調べたいときは値 in d.values()を使います。
辞書は順序を保証しないと思い込む
Python 3.7以降、辞書は追加した順番を保ちます。古い情報に惑わされないようにします。
リストをキーにしようとする
キーには変更できない値(文字列・数値・タプル)しか使えません。リストはキーにできずTypeErrorになります。
カウントでいきなり += する
初めてのキーは存在しないため、counts[w] += 1はKeyErrorになります。counts.get(w, 0) + 1のように「無ければ0」から始めます。
よくある質問
d["key"]、キーがあるか分からないときはd.get("key")です。getは存在しないキーでもエラーにならずNone(または指定した既定値)を返すため、外部から受け取ったデータの取り出しに向きます。for key, value in d.items():を使います。items()がキーと値のペアを返すため、両方を同時に受け取れます。キーだけならfor key in d:、値だけならfor value in d.values():です。値 in d.values()を使います。値 in dはキーを調べるため、値ではFalseになります。キーを調べるのか値を調べるのかで、in dとin d.values()を使い分けます。counts[w] = counts.get(w, 0) + 1が定番です。初めてのキーはget(w, 0)で0から始まるためKeyErrorになりません。より簡単には標準ライブラリのcollections.Counterも使えます。まとめ
- 辞書は
{"name": "山田"}で作り、d["name"]でキーから値を取り出します。 - 存在しないキーは
[]だとKeyError。安全に取るならd.get("key", 既定)です。 - 追加・更新はどちらも
d["key"] = 値、まとめてならupdateです。 - ループは
for key, value in d.items():。順番は保たれます(3.7以降)。 inはキーを調べます。値ならin d.values()です。- 集計は
getでカウント、setdefaultでグループ化が定番です。
辞書は、名前で値を出し入れできる便利なデータ構造です。「存在しないキーはgetで安全に」「inはキーを見る」「集計はgetとsetdefault」の3点を押さえれば、設定の管理から集計まで、幅広く活用できます。

