タイトル: 要素の削除 (辞書 Python)
SEOタイトル: Python dict から要素を削除する 5 つの方法(del / pop / popitem / clear / 内包表記)
| この記事の要点 |
|
5 つの削除方法
| 方法 | 戻り値 | キー無いとき | 用途 |
|---|---|---|---|
del d['k'] | なし | KeyError | キーが必ずある前提 |
d.pop('k') | 削除した値 | KeyError | 値を使いたい場合 |
d.pop('k', None) | 削除した値 or default | default を返す | 安全に削除 |
d.popitem() | (key, value) タプル | KeyError (空 dict) | 末尾削除(LIFO) |
d.clear() | なし | — | 全クリア |
1. del
d = {'a': 1, 'b': 2, 'c': 3}
del d['a']
print(d) # {'b': 2, 'c': 3}
# キーが無いと KeyError
del d['x'] # KeyError: 'x'
# 安全に消したい場合は in でチェック
if 'x' in d:
del d['x']
2. pop() — 値を取得しつつ削除
d = {'a': 1, 'b': 2, 'c': 3}
# 値を取得して削除
v = d.pop('a')
print(v) # 1
print(d) # {'b': 2, 'c': 3}
# キー無い + default 無し → KeyError
d.pop('x') # KeyError: 'x'
# default 指定で安全削除
v = d.pop('x', None)
print(v) # None
print(d) # {'b': 2, 'c': 3}
# よくあるイディオム
config = {'host': 'localhost', 'port': 8080}
port = config.pop('port', 80) # 取り出しつつ削除
3. popitem() — 最後の要素を取り出す
Python 3.7 以降、辞書は挿入順を保持します。popitem() は最後に追加された要素を削除して返します。
d = {'a': 1, 'b': 2, 'c': 3}
k, v = d.popitem()
print(k, v) # 'c' 3
print(d) # {'a': 1, 'b': 2}
# 空辞書では KeyError
d.popitem() # OK
d.popitem() # OK
d.popitem() # KeyError: 'dictionary is empty'
# 全要素取り出しイテレーション(LIFO)
while d:
k, v = d.popitem()
print(f'{k} = {v}')
4. clear() — 全部消す
d = {'a': 1, 'b': 2}
d.clear()
print(d) # {}
# clear と {} 代入の違い (重要)
d1 = {'a': 1}
d2 = d1 # 同じ dict を参照
d1.clear() # 元 dict を空に → d2 も空
print(d2) # {}
d1 = {'a': 1}
d2 = d1
d1 = {} # 新しい空 dict を d1 に代入 → d2 は元のまま
print(d2) # {'a': 1}
5. 条件で複数キー削除 — 内包表記が安全
イテレート中の dict を del すると RuntimeError になります:
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
# ❌ NG: イテレート中の削除
for k in d:
if d[k] % 2 == 0:
del d[k]
# RuntimeError: dictionary changed size during iteration
# ✅ OK 1: キーをリスト化してから
for k in list(d.keys()):
if d[k] % 2 == 0:
del d[k]
# ✅ OK 2: 内包表記で新しい dict
d = {k: v for k, v in d.items() if v % 2 != 0}
print(d) # {'a': 1, 'c': 3}
# ✅ OK 3: 残すキーのリストで filter
keep_keys = {'a', 'c'}
d = {k: v for k, v in d.items() if k in keep_keys}
defaultdict の挙動
defaultdict でも削除は同じですが、削除後にアクセスすると再生成される点に注意:
from collections import defaultdict
d = defaultdict(list)
d['a'].append(1)
print(d) # defaultdict(, {'a': [1]})
del d['a']
print(d) # defaultdict(, {})
# 削除済みのキーにアクセスすると default で再生成
_ = d['a']
print(d) # defaultdict(, {'a': []})
性能比較
| 操作 | 計算量 | 備考 |
|---|---|---|
| del d['k'] / pop | 平均 O(1) | ハッシュテーブル |
| popitem() | O(1) | 末尾削除 |
| clear() | O(N) | 全要素処理 |
| 内包表記で再構築 | O(N) | 全要素走査 |
FAQ
Q: ループ中に一部のキーだけ消したい
A: for k in list(d.keys()) で copy を取ってからループ、または内包表記で再構築。直接 for k in d: 中に削除すると RuntimeError。
Q: 値が None の要素だけ消す
A: d = {k: v for k, v in d.items() if v is not None}
Q: 「キーがあれば消す、無くてもエラーにしない」最短は?
A: d.pop('key', None)。1 行で済むしパフォーマンスも良好。