辞書.copy() / dict() / 辞書のマージ
| 対応: | Python 3.9(2020) |
|---|
辞書のコピー・生成・マージを行う方法をまとめています。Python 3.9以降では『|』演算子を使ったシンプルなマージも利用できます。
構文
# 辞書をシャローコピー
新辞書 = 辞書.copy()
# キーワード引数や既存の辞書から新しい辞書を生成
新辞書 = dict(キー=値, ...)
新辞書 = dict(辞書)
# アンパック演算子で複数の辞書をマージ
マージ辞書 = {**辞書1, **辞書2}
# | 演算子でマージ(Python 3.9以降)
マージ辞書 = 辞書1 | 辞書2
関数・演算子一覧
| 関数・演算子 | 概要 |
|---|---|
| 辞書.copy() | 辞書のシャローコピーを作成して返します。元の辞書を変更しても新しい辞書には影響しません(ただしネストした値は共有されます)。 |
| dict(キー=値) | キーワード引数から辞書を生成します。キーは文字列に限定されます。 |
| dict(辞書) | 既存の辞書やイテラブルから新しい辞書を生成します。 |
| {**辞書1, **辞書2} | アンパック演算子を使って複数の辞書をマージした新しい辞書を生成します。キーが重複した場合は後者の値が優先されます。 |
| 辞書1 | 辞書2 | 2つの辞書をマージした新しい辞書を返します(Python 3.9以降)。キーが重複した場合は右側の値が優先されます。 |
| 辞書1 |= 辞書2 | 辞書1に辞書2の内容をインプレースでマージします(Python 3.9以降)。 |
サンプルコード
dict_copy_merge.py
# copy() でシャローコピーを作成
original = {'name': 'member_a', 'age': 20}
copied = original.copy()
copied['name'] = 'member_b'
print(original['name']) # 『member_a』と出力されます。元の辞書は変わりません。
print(copied['name']) # 『member_b』と出力されます。
# dict() で辞書を生成
d1 = dict(name='member_c', age=24)
print(d1) # 『{'name': 'member_c', 'age': 24}』と出力されます。
# アンパック演算子でマージ
base = {'color': 'blue', 'size': 'M'}
extra = {'size': 'L', 'weight': 60}
merged = {**base, **extra}
print(merged) # 『{'color': 'blue', 'size': 'L', 'weight': 60}』と出力されます。
# | 演算子でマージ(Python 3.9以降)
d2 = {'x': 1, 'y': 2}
d3 = {'y': 99, 'z': 3}
result = d2 | d3
print(result) # 『{'x': 1, 'y': 99, 'z': 3}』と出力されます。
# |= でインプレースマージ
settings = {'theme': 'dark', 'lang': 'ja'}
overrides = {'lang': 'en', 'font': 'mono'}
settings |= overrides
print(settings) # 『{'theme': 'dark', 'lang': 'en', 'font': 'mono'}』と出力されます。
実行すると次のように出力されます。
python3 dict_copy_merge.py
member_a
member_b
{'name': 'member_c', 'age': 24}
{'color': 'blue', 'size': 'L', 'weight': 60}
{'x': 1, 'y': 99, 'z': 3}
{'theme': 'dark', 'lang': 'en', 'font': 'mono'}
よくあるミス
よくあるミス1: 浅いコピーでネストしたデータが共有される
『dict.copy()』や『{**d}』は浅いコピー(shallow copy)です。値がリストや辞書などのミュータブルオブジェクトの場合、コピー先とコピー元で同じオブジェクトを参照します。
import copy
original = {
'member_a': {'score': 950, 'tags': ['premium', 'active']},
'member_b': {'score': 900, 'tags': ['standard', 'active']},
}
# 浅いコピーはネストしたオブジェクトを共有する
shallow = original.copy()
shallow['member_a']['score'] = 999 # オリジナルも変わってしまう
print(original['member_a']['score']) # 999(意図しない変更)
次のように記述します。
# deepcopyで完全に独立したコピーを作る deep = copy.deepcopy(original) deep['member_a']['score'] = 999 print(original['member_a']['score']) # 950(変更されない)
よくあるミス2: |演算子はPython 3.9以降
辞書の『|』マージ演算子はPython 3.9以降で使えます。それ以前のバージョンでは使えません。
# Python 3.9以降のみ: | 演算子でマージ
team_a = {'member_a': 950, 'member_b': 900}
team_b = {'member_c': 880, 'member_d': 820}
merged = team_a | team_b # Python 3.9以降
# Python 3.8以前でも動く方法
merged = {**team_a, **team_b}
# または
merged = dict(team_a)
merged.update(team_b)
概要
『辞書.copy()』はシャローコピーを作成します。辞書の値が文字列や数値などの不変オブジェクトであれば、コピー後に一方を変更してももう一方に影響しません。ただし値がリストや辞書などのミュータブルオブジェクトの場合は参照が共有されるため、深いコピーが必要なときは『copy.deepcopy()』を使います。
辞書のマージには複数の方法があります。『{**d1, **d2}』はPython 3.5以降で使え、3つ以上の辞書も一度にまとめられます。Python 3.9以降では『d1 | d2』という直感的な書き方が可能です。いずれの方法でもキーが重複した場合は後から指定した辞書の値が優先されます。意図せず値が上書きされないよう注意が必要です。
辞書内包表記による生成は『辞書内包表記』を参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。