Python copy()とdeepcopy()の違い
はじめに
リストや辞書をコピーするときに利用するcopy()
関数とdeepcopy()
関数の違いをサンプルコードをもとに説明します。
結論から
リストや辞書が入れ子になっている場合、copy()
関数では内部のリストや辞書は正しくコピーされません。これに対してdeepcopy()
関数では、内部のリストや辞書も正しくコピーされます。
この振る舞いから、copy()
関数によるコピーを浅いコピー、deepcopy()
関数によるコピーを深いコピーと呼びます。
コピーとは?
ここでいうコピーとは、コピー元と参照先が異なるリストや辞書を作成することを示します。基本的にpythonの変数は参照渡しされますので、単純に変数を別の変数に代入しただけでは正しくコピーされません。
例えば以下のようにリストa、リストbを別々に作成した場合、これらはそれぞれ別の参照先に格納されます。そのためリストaの要素を変更してもリストbは変更されません。
a = ['apple', 'banana'] b = ['apple', 'banana'] a[0] = 'orange' # リストaを変更 print(a) print(b)
['orange', 'banana'] ['apple', 'banana']
これに対して、以下のようにリストaをリストbに代入した場合、リストaを変更するとリストbも変更されてしまいます。
これはリストaとリストbの参照先が同じになっていることが原因です。変数の名称が異なるだけで、実際には同じデータを示しているとも言えます。
a = ['apple', 'banana'] b = a a[0] = 'orange' # リストaを変更 print(a) print(b)
['orange', 'banana'] ['orange', 'banana']
copy()とdeepcopy()の違い
copy()は浅いコピー
まずは、copy()
関数で内部にリストを含むリストをコピーしてみます。
copy()
関数でも、一見すると内部のリストまでコピーされているように見えます。
import copy fruits = [['apple', 'banana'], ['orange', 'grape']] fruits_copy = copy.copy(fruits) print(fruits) print(fruits_copy)
[['apple', 'banana'], ['orange', 'grape']] [['apple', 'banana'], ['orange', 'grape']]
ですが、以下の通り①のようにリストの要素自体を変更した場合はコピー元に反映されませんが、②のように内部のリストの要素を変更した場合はコピー元にもその変更が反映されています。
つまり、リストの要素はコピーされているが、内部のリストの要素は参照渡しされている状態です。これを浅いコピーと言います。
import copy fruits = [['apple', 'banana'], ['orange', 'grape']] fruits_copy = copy.copy(fruits) fruits_copy[0] = ['lemon', 'melon'] # ①:リストの要素を変更 fruits_copy[1][0] = 'pineapple' # ②:リストの内部のリストを変更 print(fruits) print(fruits_copy)
[['apple', 'banana'], ['pineapple', 'grape']] [['lemon', 'melon'], ['pineapple', 'grape']]
deepcopy()は深いコピー
deepcopy()
関数を利用すれは、内部のリストも正しくコピーされます(コピー先を変更してもコピー元には影響がない)。つまり、内部のリストの要素も異なる参照になります。これを深いコピーと言います。
import copy fruits = [['apple', 'banana'], ['orange', 'grape']] fruits_copy = copy.deepcopy(fruits) fruits_copy[0] = ['lemon', 'melon'] # ①:リストの要素を変更 fruits_copy[1][0] = 'pineapple' # ②:リストの内部のリストを変更 print(fruits) print(fruits_copy)
[['apple', 'banana'], ['orange', 'grape']] [['lemon', 'melon'], ['pineapple', 'grape']]