浅いコピーと深いコピーの違い

2022年4月4日Python

ミュータブルなオブジェクトをコピーしたとき、そのオブジェクトの構造やコピーの仕方によっては挙動が大きく変わることがある。

単純にコピーはコピーじゃないんか?と思うけど一言にコピーと言っても同じではない。浅いコピーと深いコピーがある。
浅いコピー:Shallow Copy
深いコピー:Deep Copy

浅い深いってなんやねんって感じですけど、実際の挙動を見るのが早いですね。

例えば、以下のようなリストを代入したときと、浅いコピー、深いコピーしたときの挙動を見てみる。

import copy

l           = [0,1,[2,3]]
l_assign    = l
l_copy      = l.copy()
l_deepcopy  = copy.deepcopy(l)

def print_l():
  print('list:', l)
  print('assign:',l_assign)
  print('copy:',l_copy)
  print('deepcopy:',l_deepcopy)

l[0]    = 100
print_l()

l[2][0] = 300
print_l()

まず最初の

l[0]    = 100
print_l()

の出力を見ると

list: [100, 1, [2, 3]]
assign: [100, 1, [2, 3]]
copy: [0, 1, [2, 3]]
deepcopy: [0, 1, [2, 3]]

となっていて、リスト本体と代入先は同様に変更されている。 コピーした方はどちらも変わっていない。 コピーした時点で基本的には別オブジェクトとなるからで、これだけだと浅い深いの違いはわからない。

違いが出るのは、ネストされたリスト側の操作をしたとき
つまり

l[2][0] = 300
print_l()

の出力なんだけど、

list: [100, 1, [300, 3]]
assign: [100, 1, [300, 3]]
copy: [0, 1, [300, 3]]
deepcopy: [0, 1, [2, 3]]

こうなる。
浅いコピーの方にも同じ変更がされてしまっている。
つまり浅いコピーはオブジェクト中のオブジェクトはコピーされないっていうこと。
深いコピーをすれば、オブジェクト中のオブジェクトもコピーされて別オブジェクト扱いされるようになる。

Python

Posted by tsubakurame