目的
いわゆる、shallow-copyとかdeep-copyに関するもの。
表題のことを30ケースほど試してみた。
結果は、以下に示すとおり(Python 3.7.2)。
比較的複雑なので、実現したい目的に応じて、その目的の観点にまとを絞って
方法を検討するのがいいと思いました。
(目的の例:計算時間都合?で、できるだけ、実際のCOPYを少なくしたい 等)
どういう動きになるのか、汎用的に頭に入れるのはやや困難?(ワタシのレベルでは)
結果に対するコメント
listとnumpyでは、違う。
1次元と2次元では、違う。
.deepcopy()は、わかり易いと感じた。
※np.shares_memoryは、期待の動きと違う。
「listとnumpyでは、違う。」の例
【A3】と【A13】の比較でわかるように、
listのスライスは、copyになっているが、
ndarrayのスライスは。参照になっている。
(どこかで、実行速度のため、コピーを避けている的な説明を見たことがあるが、それにしては、ndarrayもその他の条件であっさりコピーしていたり
するので、理由はよくわからない。)
>>> #【A3】1次元,list,スライス
...
>>> a = [1,2,3,4]
>>> b = a[:]
>>> a[0] = 900
>>> a[1] = 99911
>>> a
[900, 99911, 3, 4]
>>> b
[1, 2, 3, 4]
>>> #【A13】1次元,ndarray,スライス
...
>>> a = np.array([1,2,3,4])
>>> b = a[:]
>>> a[0] = 900
>>> a[1] = 99911
>>> a
array([ 900, 99911, 3, 4])
>>> b
array([ 900, 99911, 3, 4])
>>> np.shares_memory(a,b)
True
上に示した【A3】と以下の【A4】をの比較すると、
違っている。
ここで、【A4】は、何もコピーされていないように見えるが、
topレベルはコピーされていることを
【A4_b】に示す。
Python Pocket Referenceの説明がわかりやすい。
(出典: Python Pocket Reference, 5th Edition
Python In Your Pocket
By Mark Lutz
Publisher: O'Reilly Media)
L.copy()
Make a top-level(shallow)copy of L. ...
>>> #【A4】2次元,list,スライス
...
>>> a = [[1,2],[3,4]]
>>> b = a[:][:]
>>> a[0][0] = 900
>>> a[1][1] = 99911
>>> a
[[900, 2], [3, 99911]]
>>> b
[[900, 2], [3, 99911]]
>>>
>>> #【A4_b】2次元,list,スライス
...
>>> a = [[1,2],[3,4]]
>>> b = a[:][:]
>>> a[0] = [900,9000]#変更
>>> #(topレベルは、コピーされていることを示すため)
... a[1][1] = 99911
>>> a
[[900, 9000], [3, 99911]]
>>> b
[[1, 2], [3, 99911]]
>>>
実行結果
>>> import numpy as np
>>> import copy
>>>
>>>
【A1】1次元,list,代入
>>> a = [1,2,3,4]
>>> b = a # 代入では
>>> a[0] = 900
>>> a[1] = 99911
>>> a # a が変われば
[900, 99911, 3, 4]
>>> b # b も変わる
[900, 99911, 3, 4]
【A2】2次元,list,代入
>>> a = [[1,2],[3,4]]
>>> b = a # 代入では
>>> a[0][0] = 900
>>> a[1][1] = 99911
>>> a # a が変われば
[[900, 2], [3, 99911]]
>>> b # b も変わる
[[900, 2], [3, 99911]]
【A3】1次元,list,スライス
>>> a = [1,2,3,4]
>>> b = a[:] # 1次元スライスでの全代入は
>>> a[0] = 900
>>> a[1] = 99911
>>> a # a が変わっても
[900, 99911, 3, 4]
>>> b # b は変わらない
[1, 2, 3, 4]
【A4】2次元,list,スライス
>>> a = [[1,2],[3,4]]
>>> b = a[:][:] # 2次元スライスでの全代入は
>>> a[0][0] = 900
>>> a[1][1] = 99911
>>> a # a が変われば
[[900, 2], [3, 99911]]
>>> b # b も変わる
[[900, 2], [3, 99911]]
【A5】1次元,list,listのcopy関数
>>> a = [1,2,3,4]
>>> b = a.copy() # 1次元の.copy() では
>>> a[0] = 900
>>> a[1] = 99911
>>> a # a が変わっても
[900, 99911, 3, 4]
>>> b # b は変わらない
[1, 2, 3, 4]
【A6】2次元,list,listのcopy関数
>>> a = [[1,2],[3,4]]
>>> b = a.copy() # 2次元の.copy() では
>>> a[0][0] = 900
>>> a[1][1] = 99911
>>> a # a が変われば
[[900, 2], [3, 99911]]
>>> b # b も変わる
[[900, 2], [3, 99911]]
【A7】1次元,list,copyモジュールのcopy関数
>>> a = [1,2,3,4]
>>> b = copy.copy(a) # copy.copy(1次元) では
>>> a[0] = 900
>>> a[1] = 99911
>>> a # a が変わっても
[900, 99911, 3, 4]
>>> b # b は変わらない
[1, 2, 3, 4]
【A8】2次元,list,copyモジュールのcopy関数
>>> a = [[1,2],[3,4]]
>>> b = copy.copy(a) # copy.copy(2次元) では
>>> a[0][0] = 900
>>> a[1][1] = 99911
>>> a # a が変わると
[[900, 2], [3, 99911]]
>>> b # b も変わる
[[900, 2], [3, 99911]]
【A9】1次元,list,copyモジュールのdeepcopy関数
>>> a = [1,2,3,4]
>>> b = copy.deepcopy(a)
>>> a[0] = 900
>>> a[1] = 99911
>>> a
[900, 99911, 3, 4]
>>> b
[1, 2, 3, 4]
【A10】2次元,list,copyモジュールのdeepcopy関数
>>> a = [[1,2],[3,4]]
>>> b = copy.deepcopy(a)
>>> a[0][0] = 900
>>> a[1][1] = 99911
>>> a
[[900, 2], [3, 99911]]
>>> b
[[1, 2], [3, 4]]
【A11】1次元,ndarray,代入
>>> a = np.array([1,2,3,4])
>>> b = a
>>> a[0] = 900
>>> a[1] = 99911
>>> a
array([ 900, 99911, 3, 4])
>>> b
array([ 900, 99911, 3, 4])
>>> np.shares_memory(a,b)
True
【A12】2次元,ndarray,代入
>>> a = np.array([[1,2],[3,4]])
>>> b = a
>>> a[0][0] = 900
>>> a[1][1] = 99911
>>> a
array([[ 900, 2],
[ 3, 99911]])
>>> b
array([[ 900, 2],
[ 3, 99911]])
>>> np.shares_memory(a,b)
True
【A13】1次元,ndarray,スライス
>>> a = np.array([1,2,3,4])
>>> b = a[:]
>>> a[0] = 900
>>> a[1] = 99911
>>> a
array([ 900, 99911, 3, 4])
>>> b
array([ 900, 99911, 3, 4])
>>> np.shares_memory(a,b)
True
【A14】2次元,ndarray,スライス
>>> a = np.array([[1,2],[3,4]])
>>> b = a[:][:]
>>> a[0][0] = 900
>>> a[1][1] = 99911
>>> a
array([[ 900, 2],
[ 3, 99911]])
>>> b
array([[ 900, 2],
[ 3, 99911]])
>>> np.shares_memory(a,b)
True
【A15】1次元,ndarray,numpyのcopy関数
>>> a = np.array([1,2,3,4])
>>> b = a.copy()
>>> a[0] = 900
>>> a[1] = 99911
>>> a
array([ 900, 99911, 3, 4])
>>> b
array([1, 2, 3, 4])
>>> np.shares_memory(a,b)
False
【A16】2次元,ndarray,numpyのcopy関数
>>> a = np.array([[1,2],[3,4]])
>>> b = a.copy()
>>> a[0][0] = 900
>>> a[1][1] = 99911
>>> a
array([[ 900, 2],
[ 3, 99911]])
>>> b
array([[1, 2],
[3, 4]])
>>> np.shares_memory(a,b)
False
【A17】1次元,ndarray,copyモジュールのcopy関数
>>> a = np.array([1,2,3,4])
>>> b = copy.copy(a)
>>> a[0] = 900
>>> a[1] = 99911
>>> a
array([ 900, 99911, 3, 4])
>>> b
array([1, 2, 3, 4])
>>> np.shares_memory(a,b)
False
【A18】2次元,ndarray,copyモジュールのcopy関数
>>> a = np.array([[1,2],[3,4]])
>>> b = copy.copy(a)
>>> a[0][0] = 900
>>> a[1][1] = 99911
>>> a
array([[ 900, 2],
[ 3, 99911]])
>>> b
array([[1, 2],
[3, 4]])
>>> np.shares_memory(a,b)
False
【A19】1次元,ndarray,copyモジュールのdeepcopy関数
>>> a = np.array([1,2,3,4])
>>> b = copy.deepcopy(a)
>>> a[0] = 900
>>> a[1] = 99911
>>> a
array([ 900, 99911, 3, 4])
>>> b
array([1, 2, 3, 4])
>>> np.shares_memory(a,b)
False
【A20】2次元,ndarray,copyモジュールのdeepcopy関数
>>> a = np.array([[1,2],[3,4]])
>>> b = copy.deepcopy(a)
>>> a[0][0] = 900
>>> a[1][1] = 99911
>>> a
array([[ 900, 2],
[ 3, 99911]])
>>> b
array([[1, 2],
[3, 4]])
>>> np.shares_memory(a,b)
False
>>> import numpy as np
>>> import copy
【B1】2次元,list,代入
>>> ee = [1,2]
>>> ff = [3,4]
>>> gg = [100,200]
>>>
>>> a = [ee,ff]
>>> b = a
>>> a[1] = gg
>>> ee[1] = 99911
>>> a
[[1, 99911], [100, 200]]
>>> b
[[1, 99911], [100, 200]]
【B2】2次元,list,スライス
>>> ee = [1,2]
>>> ff = [3,4]
>>> gg = [100,200]
>>>
>>> a = [ee,ff]
>>> b = a[:][:]
>>> a[1] = gg
>>> ee[1] = 99911
>>> a
[[1, 99911], [100, 200]]
>>> b
[[1, 99911], [3, 4]]
【B3】2次元,list,listのcopy関数
>>> ee = [1,2]
>>> ff = [3,4]
>>> gg = [100,200]
>>>
>>> a = [ee,ff]
>>> b = a.copy()
>>> a[1] = gg
>>> ee[1] = 99911
>>> a
[[1, 99911], [100, 200]]
>>> b
[[1, 99911], [3, 4]]
【B4】2次元,list,copyモジュールのcopy関数
>>> ee = [1,2]
>>> ff = [3,4]
>>> gg = [100,200]
>>>
>>> a = [ee,ff]
>>> b = copy.copy(a)
>>> a[1] = gg
>>> ee[1] = 99911
>>> a
[[1, 99911], [100, 200]]
>>> b
[[1, 99911], [3, 4]]
【B5】2次元,list,copyモジュールのdeepcopy関数
>>> ee = [1,2]
>>> ff = [3,4]
>>> gg = [100,200]
>>>
>>> a = [ee,ff]
>>> b = copy.deepcopy(a)
>>> a[1] = gg
>>> ee[1] = 99911
>>> a
[[1, 99911], [100, 200]]
>>> b
[[1, 2], [3, 4]]
【B6】2次元,ndarray,代入
>>> ee = np.array([1,2])
>>> ff = np.array([3,4])
>>> gg = np.array([100,200])
>>>
>>> a = np.array([ee,ff])
>>> b = a
>>> a[1] = gg
>>> ee[1] = 99911
>>> a
array([[ 1, 2],
[100, 200]])
>>> b
array([[ 1, 2],
[100, 200]])
>>> np.shares_memory(a,b)
True
【B7】2次元,ndarray,スライス
>>> ee = np.array([1,2])
>>> ff = np.array([3,4])
>>> gg = np.array([100,200])
>>>
>>> a = np.array([ee,ff])
>>> b = a[:]
>>> a[1] = gg
>>> ee[1] = 99911
>>> a
array([[ 1, 2],
[100, 200]])
>>> b
array([[ 1, 2],
[100, 200]])
>>> np.shares_memory(a,b)
True
【B8】2次元,ndarray,numpyのcopy関数
>>> ee = np.array([1,2])
>>> ff = np.array([3,4])
>>> gg = np.array([100,200])
>>>
>>> a = np.array([ee,ff])
>>> b = a.copy()
>>> a[1] = gg
>>> ee[1] = 99911
>>> a
array([[ 1, 2],
[100, 200]])
>>> b
array([[1, 2],
[3, 4]])
>>> np.shares_memory(a,b)
False
【B9】2次元,ndarray,copyモジュールのcopy関数
>>> ee = np.array([1,2])
>>> ff = np.array([3,4])
>>> gg = np.array([100,200])
>>>
>>> a = np.array([ee,ff])
>>> b = copy.copy(a)
>>> a[1] = gg
>>> ee[1] = 99911
>>> a
array([[ 1, 2],
[100, 200]])
>>> b
array([[1, 2],
[3, 4]])
>>> np.shares_memory(a,b)
False
【B10】2次元,ndarray,copyモジュールのdeepcopy関数
>>> ee = np.array([1,2])
>>> ff = np.array([3,4])
>>> gg = np.array([100,200])
>>>
>>> a = np.array([ee,ff])
>>> b = copy.deepcopy(a)
>>> a[1] = gg
>>> ee[1] = 99911
>>> a
array([[ 1, 2],
[100, 200]])
>>> b
array([[1, 2],
[3, 4]])
>>> np.shares_memory(a,b)
False
補足
>>>
>>>
>>>
>>> #【A4_b】2次元,list,スライス
...
>>> a = [[1,2],[3,4]]
>>> b = a[:][:]
>>> a[0] = [900,9000]#変更
>>> #(topレベルは、コピーされていることを示すため)
... a[1][1] = 99911
>>> a
[[900, 9000], [3, 99911]]
>>> b
[[1, 2], [3, 99911]]
>>>
まとめ
コメントなどあれば、お願いします。
関連(本人)
pythonをストレスなく使う!(Python Pocket Reference (O'REILLY)が、分かり易いっ)