変数や list の値をコピーするには、
実現したい内容によっていくつかの方法があります。
私はそれを知らないまま1時間近く悩んでしまったことがあるので、
ここにまとめておきます。
ここでは、以下の3パターンに分けて説明します。
- 変数の値を代入
- list の浅いコピー(
copy()
メソッド) - list の深いコピー(
deepcopy()
関数)
1. 変数の値を代入
変数の値を代入した場合のコードを例に説明します。
s = 1
# 変数の値を代入
d = s
# 代入元変数の値を変更し、その値を出力
s += 100
print("s -> ", s)
# 代入先変数の値を出力
print("d -> ", d)
実行結果は以下の通り。
s -> 101
d -> 1
実行結果を見てもわかるように、
代入元と代入先の変数は別々の変数として管理されているため、
片一方を変更しても、もう片方に影響はありません。
2. list の浅いコピー(copy()
メソッド)
続いて list のコピーを行いますが、
まずはイケてないコピー方法の例を挙げます。
s_list = [0, 1, 2]
# list を代入
d_list = s_list
# 代入元 list の値を変更し、その値を出力
s_list[0] += 100
print("s_list -> ", s_list)
# 代入先 list の値を出力
print("d_list -> ", d_list)
実行結果は以下の通り。
s_list -> [100, 1, 2]
d_list -> [100, 1, 2]
実行結果を見てもわかるように、
代入元の list を変更しただけなのに、
代入先の list の値も変更してしまっています。
つまり同一のオブジェクトを参照してしまっています。
これを回避する(別のオブジェクトを参照する)には、
d_list = s_list
という指定ではなく、
copy()
メソッドを使い、
d_list = s_list.copy()
と指定します。
具体的なコードを使って説明します。
s_list = [0, 1, 2]
# list を copy()メソッドでコピー
d_list = s_list.copy()
# 代入元 list の値を変更し、その値を出力
s_list[0] += 100
print("s_list -> ", s_list)
# 代入先 list の値を出力
print("d_list -> ", d_list)
実行結果は以下の通り。
s_list -> [100, 1, 2]
d_list -> [0, 1, 2]
今回はちゃんと別々の結果になっています。
つまり別々のオブジェクトを参照してます。
3. list の深いコピー(deepcopy()
関数)
最後に、2次元 list のコピーを行いますが、
まずは直前に説明したcopy()
メソッドを使ったイケてない例を挙げます。
s_list = [0, 1, [20, 21, 22]]
# list を copy()メソッドでコピー
d_list = s_list.copy()
# 代入元 list の値を変更し、その値を出力
s_list[0] += 100
s_list[2][0] += 100
print("s_list -> ", s_list)
# 代入先 list の値を出力
print("d_list -> ", d_list)
実行結果は以下の通り。
s_list -> [100, 1, [120, 21, 22]]
d_list -> [0, 1, [120, 21, 22]]
実行結果を見てもわかるように、
入れ子(2次元配列)になっていない部分(0番目)の値は別オブジェクトを参照していますが、
入れ子(2次元配列)になってる部分(2番目)の値は同じオブジェクトを参照しているため、
同じ値になっています。
これを回避する(別のオブジェクトを参照する)には、
copy モジュールの deepcopy() 関数を使います。
具体的なコードを使って説明します。
# copy モジュールを import
import copy
s_list = [0, 1, [20, 21, 22]]
# list を copy.deepcopy() 関数でコピー
d_list = copy.deepcopy(s_list)
# 代入元 list の値を変更し、その値を出力
s_list[0] += 100
s_list[2][0] += 100
print("s_list -> ", s_list)
# 代入先 list の値を出力
print("d_list -> ", d_list)
実行結果は以下の通り。
s_list -> [100, 1, [120, 21, 22]]
d_list -> [0, 1, [20, 21, 22]]
今回は入れ子(2次元配列)になってる部分(2番目)も含めて
別々の結果になっています。
知らないとかなりハマってしまう内容ですが(私はハマりました)、
整理して理解しておけば、難しくはない内容だと思います。
どなたかの参考になればと思います。