Pythonのシャローコピー(Shallow Copy)とディープコピー(Deep Copy)の違いを分かりやすく解説する

スポンサーリンク

今回は、「Shallow Copy」と「Deep Copy」の違いについてご紹介します。

時々、私たちはプログラム内のさまざまな変数のコピー/クローンを作成する必要があります。

これは、シャローコピーとディープコピーのどちらを使っても行うことができます。

スポンサーリンク

シャローコピー vs ディープコピー

この記事では、シャローコピーとディープコピーの違いについて勉強していきます。

それでは、はじめましょう。

シャローコピー

次のようなコードを見てみましょう。

1
2
3
4
5
6
7
l1 = [[10,20,30],[40,50,60],[70,80,90]]
l2 = list(l1)
print("list 1: ",l1)
print("list 2: ",l2)
l1.append(['I am new element'])
print("new list 1: ",l1)
print("new list 2: ",l2)

このコードの出力は次のようになります。

list 1:  [[10, 20, 30], [40, 50, 60], [70, 80, 90]]
list 2:  [[10, 20, 30], [40, 50, 60], [70, 80, 90]]
new list 1:  [[10, 20, 30], [40, 50, 60], [70, 80, 90], ['I am new element']]
new list 2:  [[10, 20, 30], [40, 50, 60], [70, 80, 90]]

l1リストを使ってl2` が作られたことがわかる。

l2リストは後で見ることができる新しい独立したリストです。

l1 に新しい要素が追加されても、l2 は変更されません。

これはシャローコピーとして知られています。

さて、次のコードを見てみましょう。

1
2
3
4
5
6
7
8
l1 = [[10,20,30],[40,50,60],[70,80,90]]
l2 = list(l1)
print("list 1: ",l1)
print("list 2: ",l2)
 
l1[2][1] = 'I am changed'
print("new list 1: ",l1)
print("new list 2: ",l2)

どのような出力になると思いますか?出力結果を読む前に、自分で試してみてください。

何か変なものがありましたか?そうです。

今回はl2も変更されています。

このコードの出力は以下のようになります。

list 1:  [[10, 20, 30], [40, 50, 60], [70, 80, 90]]
list 2:  [[10, 20, 30], [40, 50, 60], [70, 80, 90]]
new list 1:  [[10, 20, 30], [40, 50, 60], [70, 'I am changed', 90]]
new list 2:  [[10, 20, 30], [40, 50, 60], [70, 'I am changed', 90]]

この理由は、l2がl1の浅いコピーであっても、l1とl2の要素は同じメモリ位置を参照しているからです。

したがって、一方のリストの初期要素に何らかの変更を加えると、もう一方のリストも同様に変更されます。

以下のコードに示すように、 copy モジュールの copy 関数を使用して浅いコピーを作成することもできます。

出力はまったく同じに見えることがおわかりいただけると思います。

1
2
3
4
5
6
7
8
9
10
11
12
13
import copy
l1 = [[10,20,30],[40,50,60],[70,80,90]]
l2 = copy.copy(l1)
print("list 1: ",l1)
print("list 2: ",l2)
print()
l1.append(['new'])
print("new list 1: ",l1)
print("new list 2: ",l2)
print()
l1[2][1] = 'change'
print("new list 1: ",l1)
print("new list 2: ",l2)

このコードの出力は以下のようになります。

出力が前のアプローチと同じであることがわかると思います。

list 1:  [[10, 20, 30], [40, 50, 60], [70, 80, 90]]
list 2:  [[10, 20, 30], [40, 50, 60], [70, 80, 90]]
 
new list 1:  [[10, 20, 30], [40, 50, 60], [70, 80, 90], ['new']]
new list 2:  [[10, 20, 30], [40, 50, 60], [70, 80, 90]]
 
new list 1:  [[10, 20, 30], [40, 50, 60], [70, 'change', 90], ['new']]
new list 2:  [[10, 20, 30], [40, 50, 60], [70, 'change', 90]]

ディープコピー

では、次のコードを実行し、出力の違いを見てみましょう。

1
2
3
4
5
6
7
8
9
import copy
l1 = [[10,20,30],[40,50,60],[70,80,90]]
l2 = copy.deepcopy(l1)
print("list 1: ",l1)
print("list 2: ",l2)
 
l1[2][1] = 'change'
print("new list 1: ",l1)
print("new list 2: ",l2)

今回の出力を見て驚きましたか?copyモジュールと同じモジュールのdeepcopy` 関数を使うことで、両方のリストがあらゆる面で完全に独立するようになりました。

ディープコピーの出力は以下のようになります。

list 1:  [[10, 20, 30], [40, 50, 60], [70, 80, 90]]
list 2:  [[10, 20, 30], [40, 50, 60], [70, 80, 90]]
new list 1:  [[10, 20, 30], [40, 50, 60], [70, 'change', 90]]
new list 2:  [[10, 20, 30], [40, 50, 60], [70, 80, 90]]

まとめ

今日は、Pythonのシャローコピーとディープコピーについて学びました。

また、シャローコピーされたオブジェクトは、元のオブジェクトから部分的に独立しているだけであることも学びました。

一方、ディープコピーでは、オブジェクトは互いに完全に独立しています。

ディープコピーの欠点は、シャローコピーを実装するよりも遅いということです。


どちらもcopyモジュールを使って実装することができます

お読みいただきありがとうございました。

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