Python WebAcademy Blog

Pythonの辞書(dict)とは?キーと値でデータを管理する基本を初心者向けに解説

|

Pythonの辞書(dict)を、IT初心者向けにやさしく解説します。キーと値の組で持つ仕組み、角かっことgetの使い分け、items()でのループ、setdefaultによるグループ分け、キーにできる型とできない型、そして並び順が保たれるようになった経緯まで。手元で動かせるコードと表を並べながら、実務でつまずきやすいところを順番に整理していきます。

リストは番号で取り出す。ここまでは理解できたのに、辞書が出てきたとたんに手が止まった経験はありませんか。

波かっこ、コロン、キー。見慣れない記号が一度に増えるので、身構えてしまうのも無理はありません。

ところが辞書の考え方そのものは、とても素朴です。番号ではなく名前でしまう。ただそれだけの入れ物です。

そして実務のPythonでは、辞書を触らない日がありません。設定ファイル、APIの返事、集計の途中経過。気づけばいつも辞書が中心にいます。

この記事では、辞書の基本と落とし穴を、手元で動かせるコードと一緒に整理していきます。

辞書は、名前をつけてしまう入れ物

まずは形から確認しましょう。辞書は、キーと値を組にして持つデータ構造です。

キーが名札で、値が中身です。名札さえわかっていれば、何番目かを気にせず取り出せます。

言葉より動かしたほうが早いので、次のコードを写してみてください。

user = {"name": "佐藤", "age": 28, "city": "東京"}

print(user["name"])    # 佐藤
print(len(user))       # 3
print("age" in user)   # True

角かっこにキーを書くだけで、対応する値が返ってきました。user[0] のような番号は使いません。

3行目の in にも注目してください。辞書に対する in は、キーがあるかどうかを調べます。値ではありません。

リストとの違いを表にまとめておきます。どちらを使うか迷ったら、ここに戻ってきてください。

list dict
取り出し方 番号(x[0] キー(x["name"]
中身の形 値だけ キーと値の組
重複 値は重複できる キーは重複できない
向いている場面 順番に並んだデータ 名前で引きたいデータ

リストとタプルの違いから整理したい方は、先にこちらを読んでおくと全体像がつかみやすくなります。【関連記事】Pythonのリスト(list)とタプル(tuple)、どっちを使う? それぞれの違いを徹底解説

取り出し方は2つある。getを覚えると事故が減る

ここが初心者と実務者の分かれ目になるところです。値の取り出し方には角かっこと get の2種類があります。

違いは、キーが無かったときの振る舞いです。角かっこはエラーで止まり、get は代わりの値を返します。

user = {"name": "佐藤", "age": 28}

print(user.get("email"))             # None
print(user.get("email", "未登録"))   # 未登録
print(user["email"])                 # KeyError: 'email'

2行目のように、get には第2引数で初期値を渡せます。キーが無ければその値が返るので、処理を止めずに先へ進めます。

私は10年ほどエンジニアとして開発に関わってきましたが、この使い分けで一度痛い目を見ました。外部APIの返事を data["items"] で受け取っていたところ、該当データが無い日だけ items ごと省略される仕様で、夜間バッチが落ちたのです。

以来、自分の管理下にないデータは get で受けると決めています。キーの存在を保証できるかどうかが、判断の分かれ目です。

KeyErrorそのものの読み方を確認したい方は、こちらで詳しく扱っています。【関連記事】PythonでKeyErrorが出る理由とは?辞書dictで初心者がハマるポイント

初期値を入れてから使いたいときは setdefault

get には弱点があります。値を返すだけで、辞書そのものは変わりません。

空のリストを用意してから追加したい場面では、setdefault が便利です。キーが無ければ初期値を入れ、そのうえで値を返してくれます。

members = [("営業", "佐藤"), ("開発", "遠藤"), ("営業", "加藤")]

teams = {}
for dept, name in members:
    teams.setdefault(dept, []).append(name)

print(teams)
# {'営業': ['佐藤', '加藤'], '開発': ['遠藤']}

if でキーの有無を確かめる行が消えました。データをグループ分けするとき、この書き方がそのまま使えます。

取り出し方の違いを表にしておきます。迷ったらこの4行で判断できます。

書き方 キーがあるとき キーが無いとき
d["key"] 値を返す KeyErrorで止まる
d.get("key") 値を返す Noneを返す
d.get("key", 0) 値を返す 0を返す(辞書は変わらない)
d.setdefault("key", []) 値を返す 空リストを入れてから返す

ループの回し方は3種類ある

辞書をそのままforに渡すと何が出てくるか、意外と自信を持って答えられない方が多い部分です。

答えはキーです。値ではありません。

scores = {"python": 80, "sql": 65, "git": 90}

for key in scores:
    print(key)                  # python, sql, git

for key, value in scores.items():
    print(key, value)           # python 80 ...

print(sum(scores.values()))     # 235

キーと値を両方使いたいなら items() を呼びます。値だけでよければ values() です。

items() が返すのはビューと呼ばれる特別な入れ物で、元の辞書と連動しています。リストのコピーではないので、大きな辞書でも余計なメモリを使いません。

ひとつ注意点があります。ループの最中にキーを追加したり削除したりすると、実行時エラーになります。

消したいキーがあるなら、先に候補を集めてから消すか、list(scores) のようにキーの一覧をコピーしてから回してください。

追加、更新、削除の書き方

辞書は作ったあとから自由に変えられます。追加も更新も、同じ書き方で済みます。

存在しないキーに代入すれば追加、存在するキーに代入すれば上書きです。

base = {"color": "blue", "size": "M"}

base["stock"] = 5          # 追加
base["size"] = "L"         # 上書き
base.update({"color": "red"})
print(base)
# {'color': 'red', 'size': 'L', 'stock': 5}

print(base.pop("stock"))   # 5 ← 値を受け取りながら消せる
del base["color"]
print(base)                # {'size': 'L'}

update() は、別の辞書の内容をまとめて反映するメソッドです。設定のデフォルト値に利用者の指定を重ねる、といった場面でよく使います。

Python 3.9からは、辞書どうしを縦棒でつなぐ書き方も加わりました。PEP 584で導入された結合演算子です。

defaults = {"color": "blue", "size": "M"}
custom = {"size": "L"}

merged = defaults | custom
print(merged)     # {'color': 'blue', 'size': 'L'}
print(defaults)   # {'color': 'blue', 'size': 'M'} ← 元は無事

update() との違いは、元の辞書を壊さないことです。新しい辞書が返るので、設定を組み立てる処理が読みやすくなります。

同じキーがぶつかったときは、右側の値が勝ちます。上書きの向きだけ覚えておけば迷いません。

キーにできる型、できない型

辞書のキーには何でも置けるわけではありません。ここに小さな制限があります。

辞書は、キーの値そのものから保管場所を計算しています。だから途中で中身が変わる型は使えません。

ok = {("東京", "港区"): 1, 3: "three"}
print(ok[("東京", "港区")])   # 1

try:
    {["東京", "港区"]: 1}
except TypeError as e:
    print(e)
# unhashable type: 'list'

文字列、数値、タプルはキーにできます。リストや辞書はキーにできません。

unhashable という単語が出たら、変更できる型をキーにしようとしたと考えてください。座標や複合キーを扱いたいときは、リストではなくタプルにするだけで解決します。

この制限は集合(set)とまったく同じ理屈です。仕組みから理解したい方はこちらが参考になります。【関連記事】Pythonの集合(set)とは?重複の削除と高速な存在チェックを初心者向けに解説

並び順は保たれる。ただし、いつからかを知っておく

昔のPython入門書には、辞書に順番はないと書かれています。今の説明と食い違うので、混乱する方が多い部分です。

結論から言うと、現在の辞書は書いた順を保ちます。CPython 3.6で実装として順序が保たれるようになり、Python 3.7で言語仕様として正式に保証されました

つまり3.7以降を使っているなら、items() で回したときの順番は、キーを入れた順です。JSONに書き出したときの並びも予測できます。

私が新人のころは、この保証がありませんでした。辞書の順に依存したテストが環境によって落ちるという、原因のわかりにくい不具合を何度か見ています。

順番を使った小技

順序が保証されると、辞書は重複除去の道具にもなります。dict.fromkeys() を使う書き方です。

visitors = ["sato", "endo", "sato", "kato", "endo"]

print(list(dict.fromkeys(visitors)))
# ['sato', 'endo', 'kato'] ← 最初に出てきた順のまま

キーは重複できないので、結果として重複が落ちます。set() で包むより、並び順が保たれるぶん扱いやすい場面があります。

実務でよく書く形と、つまずきポイント

最後に、現場でそのまま出てくる書き方を紹介します。まずは辞書内包表記です。

リスト内包表記と同じ発想で、キーと値をコロンでつないで書きます。

prices = {"apple": 120, "banana": 80, "melon": 900}

expensive = {name: price for name, price in prices.items() if price >= 100}
print(expensive)   # {'apple': 120, 'melon': 900}

flipped = {price: name for name, price in prices.items()}
print(flipped)     # {120: 'apple', 80: 'banana', 900: 'melon'}

条件で絞り込む処理が1行に収まりました。空の辞書を作ってループで詰めるより、意図が伝わりやすくなります。

APIやJSONを扱うときも、届いたデータはほぼ辞書の形です。読み書きの手順はこちらでまとめています。【関連記事】PythonでJSONデータの扱いをマスター!API連携に必須のjsonモジュールの使い方

つまずきやすい点を表にしておきます。どれも一度知っておけば避けられるものです。

つまずきポイント 起きること 対処
無いキーを角かっこで取る KeyErrorで止まる get に初期値を渡す
ループ中にキーを消す 実行時エラーになる キーの一覧をコピーしてから回す
リストをキーにする unhashable でエラー タプルにする
値の有無を in で調べる キーしか見ていない in d.values() と書く
同じキーを2回書く あとに書いた値だけ残る 重複していないか確認する

集計や初期値の準備が毎回めんどうだと感じたら、標準ライブラリに便利な辞書が用意されています。defaultdictやCounterがそれです。【関連記事】Pythonのcollectionsとは?Counterやdefaultdictで毎日のコードが短くなる使い方を解説

今日から使える形にまとめておく

ここまでの内容を、実際に書くときの判断だけに絞って整理します。

自分で作った辞書は角かっこでよい。外から来たデータは get で受ける、という切り分けで事故はほとんど防げます。

キーと値を両方使うループでは items() を呼ぶ。値の合計や最大値がほしいなら values() を渡すだけで済みます。

グループ分けをしたくなったら setdefault を思い出してください。if を書く前に手が動くようになれば、辞書はかなり自分のものになっています。

辞書は、Pythonの中でいちばん出番の多いデータ構造です。 焦って全部を覚える必要はありません。

まずは get と items() の2つだけ、手元のコードで使ってみてください。それだけでも、エラーで止まる回数がはっきり減るはずです。

ここまでお読みいただきありがとうございました。

参考情報

次のアクション

記事で学んだ内容を実際に動かしてみよう

Python WebAcademyでは、ブラウザ上でコードを書きながら基礎から実践まで体系的に学べます。

Python WebAcademyの学習画面

あわせて読む

関連記事

ブログ一覧へ

Python学習ロードマップ

まずはこの3講座から

記事で気になったテーマを、順番に手を動かしながら学べます。

ロードマップを見る