はじめに
昔、Pythonのリストのコピーでつまずいた話になります。 同じミスがないように。。。と思い共有します。
環境
- Python 3.6.3
リストのコピー
以下のようにリストを代入しただけだと
l1 = [1, 2, 3]
l2 = l1
l2[0] = 10 #l2のみ最初の値を変えたい
print('l1:', l1)
print('l2:', l2)
実行結果
l1: [10, 2, 3]
l2: [10, 2, 3]
l2だけを変更したつもりが、l1まで変わってしまいました。
リストの場合、単純な代入だけでは同じオブジェクトを参照してしまいます。
C++を書いているときも似たようなことがあったので、
コピーをしなければならないと思いました。
ということで、以下のようなコードで
import copy
l1 = [1, 2, 3]
l2 = copy.copy(l1) #コピーを行う
l2[0] = 10
print('l1:', l1)
print('l2:', l2)
実行結果
l1: [1, 2, 3]
l2: [10, 2, 3]
コピーをすることで別のオブジェクトになり、ちゃんと
l2の値だけが変わりました。
多次元リストのコピー
多次元のリストでも同じように書いたのですが
import copy
l1 = [[1, 2, 3], [4, 5, 6]]
l2 = copy.copy(l1)
l2[0][0] = 10
print('l1:', l1)
print('l2:', l2)
実行結果
l1: [[10, 2, 3], [4, 5, 6]]
l2: [[10, 2, 3], [4, 5, 6]]
!?
l2だけを変えたつもりが、l1まで変わってしまいました。
浅いコピーと深いコピー
Python(というかプログラミング全般)には
浅いコピー copyと深いコピー deepcopyがあるようです。
浅いコピーでは、オブジェクト内のオブジェクトまでコピーをしてくれません。
深いコピーでは再帰的にコピーを行うため、以下のようなコードにしたら
import copy
l1 = [[1, 2, 3], [4, 5, 6]]
l2 = copy.deepcopy(l1) #深いコピーにする
l2[0][0] = 10
print('l1:', l1)
print('l2:', l2)
実行結果
l1: [[1, 2, 3], [4, 5, 6]]
l2: [[10, 2, 3], [4, 5, 6]]
ちゃんと
l2の値だけが変わってくれました。
まとめ
単純にコピーと言っても、浅いコピー(シャローコピー)と深いコピー(ディープコピー)がありました。
海津 純平