Python入門 浅いコピーと深いコピー(動画あり)

浅いコピーと深いコピー

Pythonではミュータブルな値のコピーのために、「浅いコピー」と「深いコピー」が存在します。

ミュータブルな例を見て見ましょう。
num = [10, 20, 30] として、num を num2に代入してid番号を調べて見ます。
numもnum2も同じid番号になります。つまりミュータブルな値は同じ場所を指しています。
注意:id番号は実行するごとに変わります。実際には下のコードのid番号と違ってきます。

num = [10, 20, 30]
num2 = num
print('num =', id(num), 'num2 =', id(num2))
print('num2の値',num2)

結果
num = 139706031453704 num2 = 139706031453704
num2の値 [10, 20, 30]

つまり次のような状態になっています。

浅いコピー (shallow copy)

ミュータブルなリスト値は要素の値を変更したら、上のようなコードで代入した別の変数の値も変わってしまうことが理解できましたら、ではそうならないためにはどうしたら良いかということになります。

そのときに使えるのがcopyモジュールにあるcopy()になります。
copy()を使用するとリストの値をコピーして違うidに保存することができます。
このようなコピーの方法を浅いコピー (shallow copy)といいます。

注意:copyは標準モジュールではありませんので、予めcopyモジュールをインポートしておく必要があります。

import copy

my_list = [1, 2, 3] 
print(id(my_list),my_list)
my_list2 = copy.copy(my_list)
print(id(my_list2),my_list2) 
my_list2.append(4)
print(id(my_list),my_list)  
print(id(my_list2),my_list2) 

結果
139661263882504 [1, 2, 3]
139661263881288 [1, 2, 3]
139661263882504 [1, 2, 3]
139661263881288 [1, 2, 3, 4]

これで、先ほどのような問題は起こらなくなりました。

深いコピー (deep copy)

次に要素の中のひとつに整数ではなく、リストの要素を入れて見ます。
このような場合に浅いコピーでは問題が起こります。
実は、copy()を使うと次の図ようなコピーが行われます。

確かにリストの値はコピーされて、my_list1とmy_list2では別のid番号となります。
しかし、リストの中にある要素の値は実はまた個別のid番号を参照しているのです。

そして、その値がイミュータブルなものなら値を変更すると新たな場所にその変更された値が入りid番号は変更されます。
そのため、my_list1とmy_list2の値は別々の値になります。

ところが、要素の値がミュータブルな値だったらここでもid番号は変わらずmy_list1とmy_list2両方が指すid番号で管理されることになります。従って、my_list1とmy_list2の値はお互いに同じ値になってしまうのです。

それを防止するために、deepcopy()が存在します。deepcopy()を使用すると要素の値が何でも問題は起こらなくなります。
このように、deepcopy()をつかたコピーのことを「深いコピー」といいます。

import copy

my_list = [1, 2, [3, 4]] 
print(id(my_list),my_list)
my_list2 = copy.deepcopy(my_list)
print(id(my_list2),my_list2) 
my_list2[2][0] = 9
print(id(my_list),my_list)  
print(id(my_list2),my_list2) 

表示
139661273909704 [1, 2, [3, 4]]
139661263530888 [1, 2, [3, 4]]
139661273909704 [1, 2, [3, 4]]
139661263530888 [1, 2, [9, 4]]

参考になった書籍

プログラミングを少しでも経験がありPython の文法を学習する場合は、「入門 Python 3」が良いと思います。長く使えます。

「退屈なことはPython にやらせよう」はオブジェクト指向の解説がないです。代わりにPythonを使った便利な実例が初心者には嬉しい内容です。正規表現から、簡単なスクレイピング 、画像操作などあります。ただし、中級者以上には少し物足りないかもしれません。

サンプルのダウンロード

ここでダウンロードする「BMI1.ipynb」ファイルは、この動画で使用したものです。

shallow_deep.ipynb

Python入門一覧