pythonのcopyとdeepcopyの違いからpython参照を見る

3879 ワード

転載:ブログ
copyとdeepcopyの違いを議論するには、pythonでの参照、pythonのメモリ管理を明らかにする必要があります.pythonのすべてのものはオブジェクトであり,規定パラメータの伝達はオブジェクトの参照である.このように言うのは難しいかもしれませんが、PHPの付与値と引用を比較すると大まかな概念があります.次の参照を参照してください.
1.pythonでは、プログラマが値を渡すか参照を渡すかを選択できません.Pythonパラメータ伝達は「伝達対象参照」方式を採用しているに違いない.実際,この方式は伝達値と伝達参照の統合に相当する.関数が辞書やリストなどの可変オブジェクトの参照を受け取ると、オブジェクトの元の値が変更されます.これは、「参照の伝達」によってオブジェクトが伝達されることに相当します.関数が数値、文字、またはメタグループなどの可変オブジェクトの参照を受信した場合、元のオブジェクトを直接変更することはできません.これは、「値の伝達」によってオブジェクトを伝達することに相当します. 
2.リストまたは辞書をコピーすると、オブジェクトリストの参照がコピーされます.参照の値を変更すると、元のパラメータが変更されます. 
3.メモリ管理を簡素化するため、Pythonは参照カウントメカニズムによって自動ゴミ回収機能を実現し、Pythonの各オブジェクトには、そのオブジェクトが異なる場所でそれぞれ何回引用されたかをカウントするための参照カウントがある.Pythonオブジェクトを1回参照するたびに、対応する参照カウントが1増加し、Pythonオブジェクトを1回破棄するたびに、対応する参照が1減少します.参照カウントがゼロの場合にのみ、Pythonオブジェクトがメモリから削除されます.
「伝値」とは、値をつけるという意味です.ではpythonパラメータ伝達には何か特別なものがありますか?例を見てみましょう.
>>> seq = [1, 2, 3] 
>>> seq_2 = seq 
>>> seq_2.append(4) 
>>> print seq, seq_2 [1, 2, 3, 4] [1, 2, 3, 4] 
>>> seq.append(5) 
>>> print seq, seq_2 [1, 2, 3, 4, 5] [1, 2, 3, 4, 5]

PHPの構文に従えばseqとseq_2この2つの変数は2つの異なる記憶アドレスに対応し、自然に異なる値に対応し、何の関係もありませんが、pythonでは確かに私たちをがっかりさせます.次の例を見てみましょう.
>>> a = 1 
>>> b = a 
>>> b = 2 
>>> print a, b 1 2 
>>> c = (1, 2) 
>>> d = c 
>>> d = (1, 2, 3) 
>>> print c, d (1, 2) (1, 2, 3)
は明らかに上記の例と衝突していますか?冒頭の引用を見ると、引用の元のオブジェクトが変更されたとき、彼ら二人は関係ありません.つまり、彼ら二人は2つの異なるオブジェクトの引用で、それぞれの引用カウントを1ずつ減算します.最初の例ではseqとseq_2はいずれも元のオブジェクト[1,2,3]というlisオブジェクトへの参照であるため、append()でもpop()でも元のオブジェクトは変更されず、その要素だけが変更されるので、b=2が新しいintオブジェクトを作成したため、第2の例を理解するのは難しくない.
次に、copyとdeepcopyの違いを例に挙げます.
>>> seq = [1, 2, 3] 
>>> seq_1 = seq 
>>> seq_2 = copy.copy(seq) 
>>> seq_3 = copy.deepcopy(seq) 
>>> seq.append(4) 
>>> print seq, seq_1, seq_2, seq_3 [1, 2, 3, 4] [1, 2, 3, 4] [1, 2, 3] [1, 2, 3] 
>>> seq_2.append(5) 
>>> print seq, seq_1, seq_2, seq_3 [1, 2, 3, 4] [1, 2, 3, 4] [1, 2, 3, 5] [1, 2, 3] 
>>> seq_3.append(6) 
>>> print seq, seq_1, seq_2, seq_3 [1, 2, 3, 4] [1, 2, 3, 4] [1, 2, 3, 5] [1, 2, 3, 6]

この例ではcopyの後と前のつながりが見えず,copyとdeepcopyの違いも見えない.では、もう一度見てみましょう.
>>> m = [1, ['a'], 2] 
>>> m_1 = m 
>>> m_2 = copy.copy(m) 
>>> m_3 = copy.deepcopy(m) 
>>> m[1].append('b') 
>>> print m, m_1, m_2, m_3 [1, ['a', 'b'], 2] [1, ['a', 'b'], 2] [1, ['a', 'b'], 2] [1, ['a'], 2] >>> m_2[1].append('c') 
>>> print m, m_1, m_2, m_3 [1, ['a', 'b', 'c'], 2] [1, ['a', 'b', 'c'], 2] [1, ['a', 'b', 'c'], 2] [1, ['a'], 2] 
>>> m_3[1].append('d') 
>>> print m, m_1, m_2, m_3 [1, ['a', 'b', 'c'], 2] [1, ['a', 'b', 'c'], 2] [1, ['a', 'b', 'c'], 2] [1, ['a', 'd'], 2]

これから区別がわかりますが、copyは1つのオブジェクトをコピーしますが、オブジェクトの属性は元のものを参照して、deepcopyは1つのオブジェクトをコピーして、オブジェクトの中の属性もコピーして、deepcopyの後は完全に別のオブジェクトです.もう1つの例を見てみましょう.
>>> m = [1, [2, 2], [3, 3]] 
>>> n = copy.copy(m) 
>>> n[1].append(2) 
>>> print m, n [1, [2, 2, 2], [3, 3]] [1, [2, 2, 2], [3, 3]] 
>>> n[1] = 0 
>>> print m, n [1, [2, 2, 2], [3, 3]] [1, 0, [3, 3]] 
>>> n[2].append(3) 
>>> print m, n [1, [2, 2, 2], [3, 3, 3]] [1, 0, [3, 3, 3]] 
>>> m[1].pop() 2 
>>> print m, n [1, [2, 2], [3, 3, 3]] [1, 0, [3, 3, 3]] 
>>> m[2].pop() 3 
>>> print m, n [1, [2, 2], [3, 3]] [1, 0, [3, 3]]