この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:9
ページ更新者:T
更新日時:2026-06-11 07:10:02

タイトル: 辞書(dict)
SEOタイトル: Python dict 完全ガイド(生成・get・内包表記・マージ・defaultdict/Counter/TypedDict)

この記事の要点
  • dict は Python のキー/値ペアコレクション。{"name": "太郎", "age": 30} のように作成
  • 安全アクセスは d.get(key, default)d[key] は未存在キーで KeyError
  • items() / keys() / values() でイテレーション。3.7+ は挿入順保証
  • 辞書内包表記 {k: v for k, v in pairs}、マージは {**a, **b} (3.5+) / a | b (3.9+)
  • 便利な派生型: defaultdict(未存在キー自動生成)/ OrderedDict(順序操作 API)/ Counter(カウント特化)/ TypedDict(型ヒント付き dict)

dict とは

dict は Python 標準のキー/値ペアを格納するハッシュマップ型です。リスト(list)が「順序付きの値の並び」なのに対し、dict はキーで値を取り出す連想配列。検索・挿入が平均 O(1) で、用途は設定値・JSON 解析結果・カウンタ・キャッシュなど極めて広範です。

Python 3.7 以降は挿入順が保証される仕様になっており、それ以前の「順序不定」は実質過去の話です(CPython 3.6 で実装、3.7 で言語仕様化)。

基本: 作成・参照・追加・削除

# 作成
user = {"name": "太郎", "age": 30, "email": "taro@example.com"}

# dict() 関数でも作成可能
user2 = dict(name="花子", age=25)

# 空 dict
empty = {}        # こちらが推奨
empty2 = dict()

# 参照
print(user["name"])         # 太郎
# print(user["unknown"])    # KeyError 例外

# 安全参照(推奨)
print(user.get("unknown"))           # None
print(user.get("unknown", "default")) # default

# 追加・更新
user["age"] = 31              # 更新
user["address"] = "東京"       # 追加

# 削除
del user["email"]
user.pop("address")           # 値を返す
user.pop("notfound", None)    # 未存在でも None で安全

# 存在判定
if "name" in user:
    print("name キーあり")

イテレーション

d = {"a": 1, "b": 2, "c": 3}

# キーで回す(デフォルト)
for k in d:
    print(k, d[k])

# キー
for k in d.keys():
    print(k)

# 値
for v in d.values():
    print(v)

# キー + 値(最もよく使う)
for k, v in d.items():
    print(f"{k}={v}")

# ソートしてイテレート
for k in sorted(d):
    print(k, d[k])

# 値でソート
for k, v in sorted(d.items(), key=lambda x: x[1], reverse=True):
    print(k, v)

辞書内包表記

# リストから dict 生成
nums = [1, 2, 3, 4, 5]
squares = {n: n*n for n in nums}
# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# 2 つのリストから
keys = ["a", "b", "c"]
vals = [10, 20, 30]
d = {k: v for k, v in zip(keys, vals)}
# zip だけなら dict(zip(keys, vals)) でも同じ

# 条件付き
even_squares = {n: n*n for n in nums if n % 2 == 0}
# {2: 4, 4: 16}

# キーと値の入れ替え
inverted = {v: k for k, v in d.items()}

# JSON / 環境変数のフィルタリング
import os
debug_envs = {k: v for k, v in os.environ.items() if k.startswith("DEBUG_")}

マージ(複数 dict の結合)

記法バージョン説明
{**a, **b}3.5+アンパックでマージ。b の値が a を上書き
a | b3.9+パイプ演算子。最も簡潔
a |= b3.9+a を破壊的に更新
a.update(b)全バージョンa を破壊的に更新
dict(a, **b)全バージョン古い書き方
a = {"x": 1, "y": 2}
b = {"y": 99, "z": 3}

# 1. アンパック (3.5+)
merged = {**a, **b}
# {"x": 1, "y": 99, "z": 3}

# 2. パイプ演算子 (3.9+)
merged2 = a | b

# 3. update(a が変わる)
a.update(b)
# a == {"x": 1, "y": 99, "z": 3}

collections モジュールの便利な派生型

from collections import defaultdict, OrderedDict, Counter

# defaultdict: 未存在キーで KeyError にならず、自動でデフォルト値生成
counts = defaultdict(int)
for word in ["apple", "banana", "apple"]:
    counts[word] += 1
# defaultdict(int, {"apple": 2, "banana": 1})

groups = defaultdict(list)
for student in [("A組", "太郎"), ("B組", "花子"), ("A組", "次郎")]:
    groups[student[0]].append(student[1])
# {"A組": ["太郎", "次郎"], "B組": ["花子"]}

# OrderedDict: 順序操作 API が追加されている
od = OrderedDict([("a", 1), ("b", 2), ("c", 3)])
od.move_to_end("a")           # a を末尾へ
od.popitem(last=False)        # 先頭を pop

# Counter: 出現回数カウント特化
c = Counter("mississippi")
# Counter({"i": 4, "s": 4, "p": 2, "m": 1})
c.most_common(2)
# [("i", 4), ("s", 4)]

TypedDict(型ヒント付き dict)

Python 3.8+ では TypedDictdict のキーと値の型を静的に表現できます。mypy 等の型チェッカーで補完・検証が効きます:

from typing import TypedDict

class User(TypedDict):
    name: str
    age: int
    email: str

def greet(u: User) -> str:
    return f"Hello {u['name']} ({u['age']})"

# OK
greet({"name": "太郎", "age": 30, "email": "taro@example.com"})

# NG(mypy がエラー検出)
greet({"name": "太郎", "age": "thirty", "email": "x"})  # age が str

# 任意キーは total=False
class PartialUser(TypedDict, total=False):
    name: str
    age: int

よく使うイディオム

# 1. 2 つのリストを dict 化
keys, vals = ["a", "b", "c"], [1, 2, 3]
d = dict(zip(keys, vals))

# 2. dict から最大値のキー
prices = {"apple": 100, "banana": 80, "melon": 500}
max_key = max(prices, key=prices.get)   # "melon"

# 3. 辞書をフィルタ
positive = {k: v for k, v in d.items() if v > 0}

# 4. 値を加工
doubled = {k: v*2 for k, v in d.items()}

# 5. JSON 化
import json
s = json.dumps(d, ensure_ascii=False, indent=2)
d2 = json.loads(s)

# 6. 1 行で頻度カウント
from collections import Counter
freq = Counter("abracadabra")

パフォーマンスのコツ

  • キーは hashable な不変オブジェクト(str / int / tuple)が必須。list / dict はキー不可
  • 大量の d[k] = d.get(k, 0) + 1defaultdict(int) または Counter の方が速い
  • キー存在判定は k in d(O(1))。k in d.keys() も同じだが冗長
  • 順序を維持したまま「最近使ったキーを末尾」にしたい → OrderedDict.move_to_end()
  • 1000 万件超の巨大 dict はメモリ消費が大きい → sqlite3 / shelve を検討

FAQ

Q: dict と list、どちらを使う?
A: キーで引きたいなら dict、順番で参照するなら list。dict も 3.7+ で順序保証だが「順序を活用する API」は list の方が豊富。

Q: dict のソート結果も dict ?
A: sorted(d.items())リストを返します。dict のまま欲しければ dict(sorted(d.items()))

Q: ネストした dict のアクセスを安全に
A: d.get("a", {}).get("b", "default")、または pydantic / dataclass + 専用クラス化を検討。