sec02 - dictのコピー
Eyecatch Data Structures
スポンサーリンク

Pythonのdictコピー時に同じオブジェクトを参照する場合の挙動

dictも、listやtupleなどと同じように変数から参照されて管理されています。ですので、d2 = d1のようにコピーした場合、同じオブジェクトを参照することになるので、要素を変更すると他方にも他方にも影響します。

d1 = {'key1': 1, 'key2': 2}

d2 = d1
d2['key2'] = 10
d2['key3'] = 30

print('d1', d1, id(d1))  # d1 {'key1': 1, 'key2': 10, 'key3': 30} 2827504193216
print('d2', d2, id(d2))  # d2 {'key1': 1, 'key2': 10, 'key3': 30} 2827504193216

PythonのdictをShallow copyで複製する方法

dictにはlistやtupleのようなスライスは使えないので、copy()メソッドを使います。これはShallow copy (シャローコピー/ 浅いコピー)ですので、ネストされたlistやdictは複製されません。

ネストされていない、またはネスト部分を編集しない場合は、copy()メソッドで解決できます。

d1 = {'key1': 1, 'key2': 2}

d2 = d1.copy()
d2['key2'] = 10
d2['key3'] = 30

print('d1', d1, id(d1))  # d1 {'key1': 1, 'key2': 2} 3208174636736
print('d2', d2, id(d2))  # d2 {'key1': 1, 'key2': 10, 'key3': 30} 3208174647808
スポンサーリンク

PythonのネストされたdictをShallow copyしたときの注意点

次のコードのような、ネストされたデータの場合の挙動を確認します。

d1 = {'profile': {'age': 10}, 'friends': ['Emma']}

d2 = d1.copy()
d2['profile']['age'] = 99
d2['friends'].append('NICOLAS')

print('d1', d1, id(d1))  # d1 {'profile': {'age': 99}, 'friends': ['Emma', 'NICOLAS']} 2464997588928
print('d2', d2, id(d2))  # d2 {'profile': {'age': 99}, 'friends': ['Emma', 'NICOLAS']} 2464997588864

print('d1["profile"]', d1['profile'], id(d1['profile']))  # d1["profile"] {'age': 99} 2464997576448
print('d2["profile"]', d2['profile'], id(d2['profile']))  # d2["profile"] {'age': 99} 2464997576448
print('d1["friends"]', d1['friends'], id(d1['friends']))  # d1["friends"] ['Emma', 'NICOLAS'] 2464997554752
print('d2["friends"]', d2['friends'], id(d2['friends']))  # d2["friends"] ['Emma', 'NICOLAS'] 2464997554752

"外側"のdictは、copy()メソッドによって複製されるので、異なるidになります。しかし、valueとして定義されたdictやlistは同じオブジェクトを参照している為、それらのオブジェクトに対して編集が行われると、他方にまで影響が及びます。

(※ただし、ネストされたオブジェクトの要素を一切変更しない場合は、Shallow copyで十分です。)

PythonのネストされたdictをDeep copyする方法とShallow copyとの違い

次に、Deep copy(ディープコピー)した時の実行結果を確認しましょう。copyモジュールのdeepcopy()関数を使用します。

import copy

d1 = {'profile': {'age': 10}, 'friends': ['Emma']}

d2 = copy.deepcopy(d1)
d2['profile']['age'] = 99
d2['friends'].append('NICOLAS')

print('d1', d1, id(d1))  # d1 {'profile': {'age': 10}, 'friends': ['Emma']} 1303331618752
print('d2', d2, id(d2))  # d2 {'profile': {'age': 99}, 'friends': ['Emma', 'NICOLAS']} 1303331618432

print('d1["profile"]', d1['profile'], id(d1['profile']))  # d1["profile"] {'age': 10} 1303331606336
print('d2["profile"]', d2['profile'], id(d2['profile']))  # d2["profile"] {'age': 99} 1303331618560
print('d1["friends"]', d1['friends'], id(d1['friends']))  # d1["friends"] ['Emma'] 1303331584640
print('d2["friends"]', d2['friends'], id(d2['friends']))  # d2["friends"] ['Emma', 'NICOLAS'] 1303331482048

ネストされたdictやlistなどのオブジェクトも含め、全てのidが異なっていることが確認できます。これで、ネストされたオブジェクトに対して編集を行っても、他方に影響を与えなくなります。

(※ ただし、全てを複製することによって、メモリ使用量や処理速度に影響が出ることがありますので、処理の内容によってShallow copyとDeep copyを使い分けましょう。)

スポンサーリンク