import copy
a = "deepak"
b = 1, 2, 3, 4
c = [1, 2, 3, 4]
d = {1: 10, 2: 20, 3: 30}
a1 = copy.copy(a)
b1 = copy.copy(b)
c1 = copy.copy(c)
d1 = copy.copy(d)
print("immutable - id(a)==id(a1)", id(a) == id(a1))
print("immutable - id(b)==id(b1)", id(b) == id(b1))
print("mutable - id(c)==id(c1)", id(c) == id(c1))
print("mutable - id(d)==id(d1)", id(d) == id(d1))
次のような結果が得られます。
immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) False
mutable - id(d)==id(d1) False
ディープコピーを行うと。
a1 = copy.deepcopy(a)
b1 = copy.deepcopy(b)
c1 = copy.deepcopy(c)
d1 = copy.deepcopy(d)
の結果は同じです。
immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) False
mutable - id(d)==id(d1) False
アサインメントオペレーションに取り組んだら。
a1 = a
b1 = b
c1 = c
d1 = d
とすると、結果は
immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) True
mutable - id(d)==id(d1) True
どなたか、コピーの違いは一体何なのか説明してください。mutable & immutable objectsに関係することなのでしょうか?もしそうなら、私にそれを説明してもらえますか?
通常の代入操作では、新しい変数を既存のオブジェクトの方に向けるだけです。浅いコピーと深いコピーの違いについては、docsに説明があります。
浅いコピーと深いコピーの違いは、次のことにのみ関係します。 複合オブジェクト(他のオブジェクトを含むオブジェクト、例えばリストや クラスインスタンス)。
シャローコピーは、新しい複合オブジェクトを構築し、(可能な範囲で)オリジナルにあるオブジェクトへの参照をその中に挿入します。
ディープコピーは、新しい複合オブジェクトを構築し、再帰的に、元のオブジェクトにあるオブジェクトのコピーをその中に挿入する。 オリジナルです。
ここで少しデモをします。
import copy
a = [1, 2, 3]
b = [4, 5, 6]
c = [a, b]
通常の割り当て操作でコピーする。
d = c
print id(c) == id(d) # True - d is the same object as c
print id(c[0]) == id(d[0]) # True - d[0] is the same object as c[0]
浅いコピーを使う。
d = copy.copy(c)
print id(c) == id(d) # False - d is now a new object
print id(c[0]) == id(d[0]) # True - d[0] is the same object as c[0]
ディープコピーを使う
d = copy.deepcopy(c)
print id(c) == id(d) # False - d is now a new object
print id(c[0]) == id(d[0]) # False - d[0] is now a new object
不変オブジェクトの場合、データは決して変化しないので、Pythonは同じデータを使用します;idは常に同じです。ミュータブルオブジェクトの場合は、潜在的に変化する可能性があるので、[浅い]コピーで新しいオブジェクトを作成します。
ディープコピーは入れ子構造に関連しています。リストのリストがある場合、ディープコピーはネストしたリストもコピーするので、再帰的なコピーとなります。ただのコピーでは、新しい外側のリストができますが、内側のリストは参照になります。
アサインメントではコピーしません。単に古いデータへの参照を設定するだけです。ですから、同じ内容の新しいリストを作成するには、コピーが必要です。
不変のオブジェクトの場合、コピーを作成しても、変更されないため、あまり意味がありません。 可変オブジェクトの場合、assignment
、copy
、およびdeepcopy
の動作は異なります。 それぞれについて例を挙げて話しましょう。
割り当て操作では、ソースの参照を目的地に割り当てるだけです。
>>> i = [1,2,3]
>>> j=i
>>> hex(id(i)), hex(id(j))
>>> ('0x10296f908', '0x10296f908') #Both addresses are identical
ここで、 i
と j
は技術的に同じリストを参照します。 i
とj
はどちらも同じメモリアドレスを持っています。 どちらかへの更新。
それらのうち、他のものに反映されます。 例えば:
>>> i.append(4)
>>> j
>>> [1,2,3,4] #Destination is updated
>>> j.append(5)
>>> i
>>> [1,2,3,4,5] #Source is updated
一方、「コピー」と「ディーコピー」は変数の新しいコピーを作成します。 したがって、元の変数への変更は反映されません。 コピー変数に、またはその逆。 ただし、「copy(shallow copy)」では、ネストされたオブジェクトのコピーを作成するのではなく、単に作成します。 ネストされたオブジェクトのリファレンスをコピーします。 Deepcopyは、ネストされたすべてのオブジェクトを再帰的にコピーします。
「コピー」と「ディーコピー」の動作を示すいくつかの例:
copy
を使用したフラットリストの例:。
>>> import copy
>>> i = [1,2,3]
>>> j = copy.copy(i)
>>> hex(id(i)), hex(id(j))
>>> ('0x102b9b7c8', '0x102971cc8') #Both addresses are different
>>> i.append(4)
>>> j
>>> [1,2,3] #Updation of original list didn't affected copied variable
copy
を使用したネストされたリストの例:。
>>> import copy
>>> i = [1,2,3,[4,5]]
>>> j = copy.copy(i)
>>> hex(id(i)), hex(id(j))
>>> ('0x102b9b7c8', '0x102971cc8') #Both addresses are still different
>>> hex(id(i[3])), hex(id(j[3]))
>>> ('0x10296f908', '0x10296f908') #Nested lists have same address
>>> i[3].append(6)
>>> j
>>> [1,2,3,[4,5,6]] #Updation of original nested list updated the copy as well
deepcopy
を使用したフラットリストの例:。
>>> import copy
>>> i = [1,2,3]
>>> j = copy.deepcopy(i)
>>> hex(id(i)), hex(id(j))
>>> ('0x102b9b7c8', '0x102971cc8') #Both addresses are different
>>> i.append(4)
>>> j
>>> [1,2,3] #Updation of original list didn't affected copied variable
deepcopy
を使用したネストされたリストの例:。
>>> import copy
>>> i = [1,2,3,[4,5]]
>>> j = copy.deepcopy(i)
>>> hex(id(i)), hex(id(j))
>>> ('0x102b9b7c8', '0x102971cc8') #Both addresses are still different
>>> hex(id(i[3])), hex(id(j[3]))
>>> ('0x10296f908', '0x102b9b7c8') #Nested lists have different addresses
>>> i[3].append(6)
>>> j
>>> [1,2,3,[4,5]] #Updation of original nested list didn't affected the copied variable
a、b、c、d、a1、b1、c1、d1 はメモリ上のオブジェクトへの参照で、id で一意に識別される。
代入操作は、メモリ上のオブジェクトへの参照を取り、その参照を新しい名前に代入する。 c=[1,2,3,4]は、これら4つの整数を含む新しいリストオブジェクトを作成し、そのオブジェクトへの参照を
cに代入する代入である。 c1=c
は、同じオブジェクトへの同じ参照を取り、それを c1
に代入する代入です。 リストはミュータブルであるため、同じオブジェクトを参照している c
と c1
のどちらからアクセスしても、そのリストに起こったことはすべて目に見えるものとなります。
c1=copy.copy(c)は "shallow copy" で、新しいリストを作成し、その新しいリストへの参照を
c1に割り当てます。 c
はまだ元のリストを指しています。 したがって、c1
のリストを変更しても、c
が参照するリストは変更されない。
整数や文字列のような不変のオブジェクトには、コピーの概念は関係ありません。 これらのオブジェクトは変更できないので、同じ値のコピーを2つ、メモリ上の異なる場所に置く必要はありません。 ですから、整数や文字列、そしてコピーの概念が適用されない他のいくつかのオブジェクトは、単に再割り当てされます。 このため、a
とb
を使った例では、同じIDになるのです。
c1=copy.deepcopy(c)`はquot;deep copy"ですが、この例では浅いコピーと同じように機能します。 ディープコピーはシャローコピーと異なり、シャローコピーはオブジェクト自体の新しいコピーを作成しますが、そのオブジェクトの 内部 の参照はそれ自体コピーされることはありません。 この例では、リストの内部には整数しかなく(これは不変)、先に述べたように、これらをコピーする必要はありません。 ですから、ディープコピーのquot;deep"の部分は適用されません。 しかし、より複雑なこのリストを考えてみましょう。
e = [[1, 2],[4, 5, 6],[7, 8, 9]]
これは、他のリストを含むリストです(2次元配列と表現することもできます)。
eに対して "shallow copy" を実行して
e1にコピーすると、リストの id は変わりますが、リストの各コピーには同じ 3 つのリスト(内部に整数を含むリスト)への参照が含まれていることがわかります。 つまり、
e[0].append(3)とすると、
eは
[[1, 2, 3],[4, 5, 6],[7, 8, 9]]となります。 しかし、
e1も
[[1, 2, 3],[4, 5, 6],[7, 8, 9]]となります。 一方、その後
e.append([10, 11, 12])を実行した場合、
eは
[[1, 2, 3],[4, 5, 6],[7, 8, 9],[10, 11, 12]]となるはずです。 しかし、
e1はまだ
[[1, 2, 3],[4, 5, 6],[7, 8, 9]]となります。 これは、外側リストが、最初は3つの内側リストへの3つの参照を含む別々のオブジェクトであるためです。 内側のリストを変更した場合、片方のコピーを通して見ても、もう片方のコピーを通して見ても、その変更を見ることができます。 しかし、上記のように外側リストの1つを変更すると、
eは元の3つのリストへの3つの参照と新しいリストへのもう1つの参照を含むことになります。 そして、
e1`はまだ元の3つの参照しか含んでいません。
ディープコピー'は外側のリストを複製するだけでなく、リストの内部に入り込んで内側のリストを複製するので、出来上がった2つのオブジェクトには(ミュータブルオブジェクトに関する限り)同じ参照は含まれません。 もし内側のリストの中にさらにリスト(または辞書などの他のオブジェクト)があれば、それらも複製されることになります。 これが 'ディープコピー の 'ディープ'の部分です。
pythonでは、リスト、タプル、ディクテクトなどのオブジェクトを、通常は '='記号の別のオブジェクトに割り当てると、pythonは参照によりコピーを作成します。 つまり、次のようなリストのリストがあるとします。
list1 = [ [ 'a' , 'b' , 'c' ] , [ 'd' , 'e' , 'f' ] ]
次のような別のリストをこのリストに割り当てます。
list2 = list1
次に、python端末でlist2を印刷すると、次のようになります。
list2 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] ]
両方のリスト1とlist2は同じメモリ位置を指しています。それらのいずれかに変更すると、両方のオブジェクトに表示される変更になります。つまり、両方のオブジェクトが同じメモリ位置を指しています。 このようにlist1を変更した場合:
list1[0][0] = 'x’
list1.append( [ 'g'] )
次に、list1とlist2の両方が次のようになります。
list1 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g'] ]
list2 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g’ ] ]
Shallow copy になると、2つのオブジェクトが浅いコピーを介してコピーされると、両方の親オブジェクトの子オブジェクトは同じメモリ位置を参照しますが、コピーされたオブジェクトのいずれかの新しい変更は互いに独立します。 これを小さな例で理解しましょう。 この小さなコードスニペットがあるとします。
import copy
list1 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] ] # assigning a list
list2 = copy.copy(list1) # shallow copy is done using copy function of copy module
list1.append ( [ 'g', 'h', 'i'] ) # appending another list to list1
print list1
list1 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g', 'h', 'i'] ]
list2 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] ]
通知、list2は影響を受けませんが、次のような子オブジェクトに変更を加えると、
list1[0][0] = 'x’
次に、list1とlist2の両方が変更されます。
list1 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g', 'h', 'i'] ]
list2 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] ]
これで、 Deep copy は、完全に分離されたオブジェクトを互いに作成するのに役立ちます。 2つのオブジェクトがDeep Copy経由でコピーされる場合、親と子の両方が異なるメモリ位置を指しています。 例:
import copy
list1 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] ] # assigning a list
list2 = deepcopy.copy(list1) # deep copy is done using deepcopy function of copy module
list1.append ( [ 'g', 'h', 'i'] ) # appending another list to list1
print list1
list1 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g', 'h', 'i'] ]
list2 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] ]
通知、list2は影響を受けませんが、次のような子オブジェクトに変更を加えると、
list1[0][0] = 'x’
次に、list2も影響を受けません。すべての子オブジェクトと親オブジェクトが異なるメモリ位置を指しているためです。
list1 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g', 'h', 'i'] ]
list2 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f ' ] ]
それが役立つことを願っています。
上記で言及したかどうかはわかりませんが、.copy()が元のオブジェクトへの参照を作成することを非公開にすることは非常に重要です。 コピーしたオブジェクトを変更した場合-元のオブジェクトを変更します。 .deepcopy()は新しいオブジェクトを作成し、元のオブジェクトを新しいオブジェクトに実際にコピーします。 新しいディープコピーオブジェクトを変更しても、元のオブジェクトには影響しません。
そして、はい、.deepcopy()は元のオブジェクトを再帰的にコピーし、.copy()は元のオブジェクトの第1レベルのデータへの参照オブジェクトを作成します。
したがって、.copy()と.deepcopy()の間のコピー/参照の違いは重要です。
以下のコードは、割り当て、コピー方法を使用した浅いコピー、(スライス)[:]を使用した浅いコピー、およびディープコピーの違いを示しています。 以下の例では、違いをより明確にすることにより、ネストされたリストを使用しています。
from copy import deepcopy
########"List assignment (does not create a copy) ############
l1 = [1,2,3, [4,5,6], [7,8,9]]
l1_assigned = l1
print(l1)
print(l1_assigned)
print(id(l1), id(l1_assigned))
print(id(l1[3]), id(l1_assigned[3]))
print(id(l1[3][0]), id(l1_assigned[3][0]))
l1[3][0] = 100
l1.pop(4)
l1.remove(1)
print(l1)
print(l1_assigned)
print("###################################")
########"List copy using copy method (shallow copy)############
l2 = [1,2,3, [4,5,6], [7,8,9]]
l2_copy = l2.copy()
print(l2)
print(l2_copy)
print(id(l2), id(l2_copy))
print(id(l2[3]), id(l2_copy[3]))
print(id(l2[3][0]), id(l2_copy[3][0]))
l2[3][0] = 100
l2.pop(4)
l2.remove(1)
print(l2)
print(l2_copy)
print("###################################")
########"List copy using slice (shallow copy)############
l3 = [1,2,3, [4,5,6], [7,8,9]]
l3_slice = l3[:]
print(l3)
print(l3_slice)
print(id(l3), id(l3_slice))
print(id(l3[3]), id(l3_slice[3]))
print(id(l3[3][0]), id(l3_slice[3][0]))
l3[3][0] = 100
l3.pop(4)
l3.remove(1)
print(l3)
print(l3_slice)
print("###################################")
########"List copy using deepcopy ############
l4 = [1,2,3, [4,5,6], [7,8,9]]
l4_deep = deepcopy(l4)
print(l4)
print(l4_deep)
print(id(l4), id(l4_deep))
print(id(l4[3]), id(l4_deep[3]))
print(id(l4[3][0]), id(l4_deep[3][0]))
l4[3][0] = 100
l4.pop(4)
l4.remove(1)
print(l4)
print(l4_deep)
print("##########################")
print(l4[2], id(l4[2]))
print(l4_deep[3], id(l4_deep[3]))
print(l4[2][0], id(l4[2][0]))
print(l4_deep[3][0], id(l4_deep[3][0]))
取るGISTはこれです: 「通常の割り当て」を使用して浅いリスト(サブリストではなく、単一の要素のみ)を処理すると、浅いリストを作成し、「通常の割り当て」を使用してこのリストのコピーを作成すると、「副作用」が発生します。 この「副作用」は、作成されたコピーリストの要素を変更する場合です。これは、元のリストの同じ要素を自動的に変更するためです。 コピー要素を変更するときに元のリスト要素を変更しないため、「コピー」が重宝します。
一方、「コピー」にはリスト(sub_lists)を含むリストがあり、「ディープコピー」がそれを解決する場合にも、「副作用」があります。 たとえば、ネストされたリスト(sub_lists)を含む大きなリストを作成し、この大きなリスト(元のリスト)のコピーを作成する場合。 「サイドエフェクト」は、コピーリストのサブリストを変更すると発生します。これにより、大きなリストのサブリストが自動的に変更されます。 (一部のプロジェクトでは)大きなリスト(元のリスト)を変更せずに保持したい場合があります。必要なのは、その要素(sub_lists)のコピーを作成することだけです。 そのための解決策は、この「副作用」を処理し、元のコンテンツを変更せずにコピーを作成する「ディープコピー」を使用することです。
「コピー」と「ディープコピー」操作のさまざまな動作は、複合オブジェクト(つまり、リストなどの他のオブジェクトを含むオブジェクト)のみに関係します。
この単純なコードの例に示されている違いは次のとおりです。
最初。
元のリストとこのリストのコピーを作成して、「コピー」(浅い)の動作を確認しましょう。
import copy
original_list = [1, 2, 3, 4, 5, ['a', 'b']]
copy_list = copy.copy(original_list)
次に、「印刷」テストをいくつか実行して、元のリストがそのコピーリストと比較してどのように動作するかを確認しましょう。
original_listとcopy_listには異なるアドレスがあります。
print(hex(id(original_list)), hex(id(copy_list))) # 0x1fb3030 0x1fb3328
original_listとcopy_listの要素には同じアドレスがあります。
print(hex(id(original_list[1])), hex(id(copy_list[1]))) # 0x537ed440 0x537ed440
original_listとcopy_listのsub_elementsには同じアドレスがあります。
print(hex(id(original_list[5])), hex(id(copy_list[5]))) # 0x1faef08 0x1faef08
original_list要素を変更しても、copy_list要素は変更されません。
original_list.append(6)
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b']]
copy_list要素を変更しても、original_list要素は変更されません。
copy_list.append(7)
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b'], 7]
original_list sub_elementsを変更すると、copy_list sub_elementsが自動的に変更されます。
original_list[5].append('c')
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c'], 7]
copy_list sub_elementsを変更すると、original_list sub_elementsが自動的に変更されます。
copy_list[5].append('d')
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c', 'd'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c', 'd'], 7]
2番目。
「コピー」で行ったのと同じことを実行して、「ディープコピー」の動作を確認しましょう(元のリストとこのリストのコピーを作成します)。
import copy
original_list = [1, 2, 3, 4, 5, ['a', 'b']]
copy_list = copy.copy(original_list)
次に、「印刷」テストをいくつか実行して、元のリストがそのコピーリストと比較してどのように動作するかを確認しましょう。
import copy
original_list = [1, 2, 3, 4, 5, ['a', 'b']]
copy_list = copy.deepcopy(original_list)
original_listとcopy_listには異なるアドレスがあります。
print(hex(id(original_list)), hex(id(copy_list))) # 0x1fb3030 0x1fb3328
original_listとcopy_listの要素には同じアドレスがあります。
print(hex(id(original_list[1])), hex(id(copy_list[1]))) # 0x537ed440 0x537ed440
original_listとcopy_listのsub_elementsには異なるアドレスがあります。
print(hex(id(original_list[5])), hex(id(copy_list[5]))) # 0x24eef08 0x24f3300
original_list要素を変更しても、copy_list要素は変更されません。
original_list.append(6)
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b']]
copy_list要素を変更しても、original_list要素は変更されません。
copy_list.append(7)
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b'], 7]
original_list sub_elementsを変更しても、copy_list sub_elementsは変更されません。
original_list[5].append('c')
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b'], 7]
copy_list sub_elementsを変更しても、original_list sub_elementsは変更されません。
copy_list[5].append('d')
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c', 'd'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b', 'd'], 7]
>>lst=[1,2,3,4,5]
>>a=lst
>>b=lst[:]
>>> b
[1, 2, 3, 4, 5]
>>> a
[1, 2, 3, 4, 5]
>>> lst is b
False
>>> lst is a
True
>>> id(lst)
46263192
>>> id(a)
46263192 ------> See here id of a and id of lst is same so its called deep copy and even boolean answer is true
>>> id(b)
46263512 ------> See here id of b and id of lst is not same so its called shallow copy and even boolean answer is false although output looks same.