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

タイトル: 要素の追加と更新
SEOタイトル: Python 辞書 (dict) の追加・更新・削除 — d[k]=v / update() / |= / pop()

この記事の要点
  • 追加・更新は同じ構文 d["key"] = value。キーがあれば上書き、無ければ追加
  • 複数同時に書き込むなら d.update({...}) またはキーワード引数版 d.update(k1=v1, k2=v2)
  • Python 3.9+ では マージ演算子 d |= {...}、新規 dict なら d3 = d1 | d2
  • 削除は del d["key"] または d.pop("key", default) (取り出して削除)
  • 初期化付き追加は d.setdefault("key", value)、辞書内包表記 {k: v for ...} で一括構築

追加と更新は同じ構文

d = {"name": "Taro"}

# キーが無ければ追加
d["age"] = 25
# {'name': 'Taro', 'age': 25}

# キーがあれば上書き (更新)
d["name"] = "Jiro"
# {'name': 'Jiro', 'age': 25}

# Python 3.7+ では挿入順を保持
for k in d:
    print(k)
# name
# age

update() で複数同時更新

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

# 別 dict をマージ (重複キーは引数側で上書き)
d.update({"b": 20, "c": 3})
# {'a': 1, 'b': 20, 'c': 3}

# キーワード引数で
d.update(d=4, e=5)
# {'a': 1, 'b': 20, 'c': 3, 'd': 4, 'e': 5}

# タプルのリストでも OK
d.update([("f", 6), ("g", 7)])

# 戻り値は None — d 自体を直接書き換える
result = d.update({"x": 1})
print(result)            # None

3.9+ のマージ演算子 (|, |=)

# Python 3.9 で導入
d1 = {"a": 1, "b": 2}
d2 = {"b": 20, "c": 3}

# 新しい dict を作る (元は変更しない)
merged = d1 | d2
# {'a': 1, 'b': 20, 'c': 3}

# 既存 dict にマージ (update() と同等、戻り値は None ではなく d 自身)
d1 |= d2
# d1 == {'a': 1, 'b': 20, 'c': 3}

# 3.8 以前は ** アンパックで近い書き方
merged = {**d1, **d2}

削除 — del / pop / popitem / clear

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

# 明示的削除 — キーが無いと KeyError
del d["a"]
# {'b': 2, 'c': 3}

# pop() は値を取り出しつつ削除
v = d.pop("b")          # v == 2、d == {'c': 3}

# pop() にデフォルトを渡せば KeyError 回避
v = d.pop("zzz", None)  # v == None

# popitem() は最後に追加された要素を取り出して削除 (LIFO)
last_k, last_v = d.popitem()
# Python 3.7+ では「最後に挿入されたペア」が確定動作

# clear() で全削除
d.clear()
# {}

setdefault — 「初期化と同時に追加」

d = {}

# キーが無ければ追加して値を返す、あれば既存値を返す
d.setdefault("count", 0)        # 0
d.setdefault("count", 100)      # 0 — 既存値は変えない
# d == {'count': 0}

# ネスト dict の構築
users = {}
users.setdefault("taro", {})["age"] = 25
users.setdefault("taro", {})["city"] = "Tokyo"
# users == {'taro': {'age': 25, 'city': 'Tokyo'}}

辞書内包表記で一括構築

# 1〜5 の二乗
squares = {n: n*n for n in range(1, 6)}
# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# キーバリュー入れ替え
d = {"a": 1, "b": 2, "c": 3}
inv = {v: k for k, v in d.items()}
# {1: 'a', 2: 'b', 3: 'c'}

# 条件付き
positives = {k: v for k, v in d.items() if v > 1}
# {'b': 2, 'c': 3}

# 既存 dict のフィルタ更新
d = {k: v.strip() for k, v in d.items() if isinstance(v, str)}

反復中の追加・削除は禁物

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

# ❌ 反復中に削除 → RuntimeError: dictionary changed size during iteration
for k in d:
    if d[k] > 1:
        del d[k]

# ✅ キー一覧をリスト化して反復
for k in list(d.keys()):
    if d[k] > 1:
        del d[k]

# ✅ 内包表記で新 dict を作って差し替え
d = {k: v for k, v in d.items() if v <= 1}

TypedDict で型を付ける

Python 3.8+ では TypedDict で「辞書のキーと値の型」を静的に検査できます (実行時は普通の dict)。

from typing import TypedDict

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

# 構築
u: User = {&quot;name&quot;: &quot;Taro&quot;, &quot;age&quot;: 25, &quot;email&quot;: &quot;taro@example.com&quot;}

# 型チェックが効く (mypy / pyright)
u[&quot;age&quot;] = &quot;25&quot;          # ← mypy: Argument has incompatible type
u[&quot;zzz&quot;] = &quot;x&quot;           # ← mypy: TypedDict &quot;User&quot; has no key 'zzz'

# 一部のキーを任意にしたい場合
class User(TypedDict, total=False):
    name: str
    email: str

パフォーマンスメモ

操作平均計算量
追加 / 更新 d[k]=vO(1)
削除 del d[k]O(1)
取得 d[k]O(1)
存在判定 k in dO(1)
全要素反復O(n)
copy() / 内包表記O(n)

キーはハッシュ可能 (immutable) でなければなりません。タプルは OK、リストや別の dict は不可。

FAQ

Q: update() と |= の違いは?
A: 動作は同じです。|= は Python 3.9+ で使え、より読みやすい新構文。古い環境を考慮するなら update()

Q: 「キーが既存ならスキップ、新規なら追加」したい
A: d.setdefault(k, v) がそのまま使えます。あるいは if k not in d: d[k] = v

Q: 辞書をコピーして元を残したい
A: 浅いコピーは d.copy() または dict(d)、深いコピーは copy.deepcopy(d)|=update() は元 dict を書き換えるので注意。