【Python】リストの浅いコピーと深いコピーの実装方法

スポンサーリンク
【Python】リストの浅いコピーと深いコピーの実装方法 基礎
この記事を読んで分かること
  • リストの浅いコピーの実装方法
  • リストの深いコピーの実装方法

 

浅いコピー

浅いコピーは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の中身

 

まとめ

浅いコピーでは、オブジェクト内の要素値渡しとなりますが、オブジェクト内のオブジェクト参照渡しとなります。

深いコピーでは、オブジェクトはすべて値渡しとなります。

 

コピー後のオブジェクトの挙動
操作内容 実装方法 変更後の結果
l[0] = 100
l[3][0] = 400
コピー元
l = [1, 2, 3, [4, 5]] [100, 2, 3, [400, 5]]
 代入
l_assign = l [100, 2, 3, [400, 5]]
浅いコピー
l_shallow = copy.copy(l)
または
l_shallow = l.copy()
[1, 2, 3, [400, 5]]
深いコピー
l_deep = copy.deepcopy(l) [1, 2, 3, [4, 5]]

 

参考文献

copy --- 浅いコピーおよび深いコピー操作
ソースコード: Lib/copy.py Python において代入文はオブジェクトをコピーしません。代入はターゲットとオブジェクトの間に束縛を作ります。ミュータブルなコレクションまたはミュータブルなアイテムを含むコレクションについては、元のオブジェクトを変更せずにコピーを変更できるように、コピーが必要になることが時々あ...

コメント

タイトルとURLをコピーしました