浅いコピー
浅いコピーはcopyライブラリのcopy()関数またはlistオブジェクトのcopy()メソッドで実装することができます。
import copy
l = [1, 2, 3, [4, 5]]
l_shallow = copy.copy(l) # l_shallow = l.copy() でも同じ
print(l_shallow)
[1, 2, 3, [4, 5]]
pythonの浅いコピーでもlist自体は別のオブジェクトが作成されます。
print(f"{id(l)} : lのアドレス")
print(f"{id(l_shallow)} : l_shallowのアドレス")
139699991175744 : lのアドレス
139699991262720 : l_shallowのアドレス
ただし、要素内のオブジェクトは参照渡しです。
そのため、リスト内のリストはコピー元のアドレスと同じになっています。
print(f"{id(l[3])} : l[3]のアドレス")
print(f"{id(l_shallow[3])} : l_shallow[3]のアドレス")
139699991152896 : l[3]のアドレス
139699991152896 : l_shallow[3]のアドレス
コピー元のリスト内の値を更新してもコピー先には影響ありませんが、
リスト内のオブジェクトを更新するとコピー先にも影響します。
l[0] = 100
l[3][0] = 400
print(f"{l} : lの中身")
print(f"{l_shallow} : l_shallowの中身")
[100, 2, 3, [400, 5]] : lの中身
[1, 2, 3, [400, 5]] : l_shallowの中身
深いコピー
深いコピーはcopyライブラリのdeepcopy()関数で実装することができます。
import copy
l = [1, 2, 3, [4, 5]]
l_deep = copy.deepcopy(l)
print(l_deep)
[1, 2, 3, [4, 5]]
深いコピーではlistも要素内のオブジェクトのどちらも別のオブジェクトが作成されます。
つまり、リスト自体・リスト内のリストのどちらも別のアドレスとなります。
print(f"{id(l)} : lのアドレス")
print(f"{id(l_shallow)} : l_shallowのアドレス")
139699991175744 : lのアドレス
139699991262720 : l_shallowのアドレス
どのオブジェクトもコピー元とは別のアドレスになっています。
print(f"{id(l)} : lのアドレス")
print(f"{id(l_deep)} : l_deepのアドレス")
print(f"{id(l[3])} : l[3]のアドレス")
print(f"{id(l_deep[3])} : l_deep[3]のアドレス")
139884247404800 : lのアドレス
139884469127168 : l_deepのアドレス
139884247489600 : l[3]のアドレス
139884247468224 : l_deep[3]のアドレス
深いコピーの場合には、リスト内の値・オブジェクトのどちらを更新してもコピー先に影響は与えません。
l[0] = 100
l[3][0] = 400
print(f"{l} : lの中身")
print(f"{l_deep} : l_deepの中身")
[100, 2, 3, [400, 5]] : lの中身
[1, 2, 3, [4, 5]] : l_deepの中身
まとめ
浅いコピーでは、オブジェクト内の要素は値渡しとなりますが、オブジェクト内のオブジェクトは参照渡しとなります。
深いコピーでは、オブジェクトはすべて値渡しとなります。
参考文献
copy --- 浅いコピーおよび深いコピー操作
ソースコード: Lib/copy.py Python において代入文はオブジェクトをコピーしません。代入はターゲットとオブジェクトの間に束縛を作ります。ミュータブルなコレクションまたはミュータブルなアイテムを含むコレクションについては、元のオブジェクトを変更せずにコピーを変更できるように、コピーが必要になることが時々あ...
コメント