dict.copy()を理解する-浅いですか、深いですか?


429

のドキュメントを読んでいる間dict.copy()、辞書の浅いコピーを作成すると書かれています。私がフォローしている本(BeazleyのPythonリファレンス)についても同じことが言えます。

m.copy()メソッドは、マッピングオブジェクトに含まれる項目の浅いコピーを作成し、それらを新しいマッピングオブジェクトに配置します。

このことを考慮:

>>> original = dict(a=1, b=2)
>>> new = original.copy()
>>> new.update({'c': 3})
>>> original
{'a': 1, 'b': 2}
>>> new
{'a': 1, 'c': 3, 'b': 2}

そのoriginalため、浅いコピーを行っていたため、これにより値が更新される(そして「c」が追加される:3)と想定しました。あなたがリストのためにそれをするかのように:

>>> original = [1, 2, 3]
>>> new = original
>>> new.append(4)
>>> new, original
([1, 2, 3, 4], [1, 2, 3, 4])

これは期待どおりに機能します。

どちらも浅いコピーなので、なぜdict.copy()期待どおりに動作しないのですか?または、浅いコピーと深いコピーの私の理解に欠陥がありますか?


2
彼らが「浅い」ことを説明しないのは趣のあることです。インサイダーの知識、ウィンク。dictとキーだけがコピーですが、その最初のレベル内のネストされたdictは参照であり、たとえばループで削除することはできません。したがって、その場合のPythonのdict.copy()は有用でも直観的でもありません。ご質問ありがとうございます。
gseattle 2017年

回答:


990

「浅いコピー」とは、辞書の内容が値によってコピーされるのではなく、新しい参照を作成することを意味します。

>>> a = {1: [1,2,3]}
>>> b = a.copy()
>>> a, b
({1: [1, 2, 3]}, {1: [1, 2, 3]})
>>> a[1].append(4)
>>> a, b
({1: [1, 2, 3, 4]}, {1: [1, 2, 3, 4]})

対照的に、ディープコピーはすべてのコンテンツを値でコピーします。

>>> import copy
>>> c = copy.deepcopy(a)
>>> a, c
({1: [1, 2, 3, 4]}, {1: [1, 2, 3, 4]})
>>> a[1].append(5)
>>> a, c
({1: [1, 2, 3, 4, 5]}, {1: [1, 2, 3, 4]})

そう:

  1. b = a:参照割り当て、作成、aおよびb同じオブジェクトを指します。

    「a = b」の例:「a」と「b」はどちらも「{1:L}」を指し、「L」は「[1、2、3]」を指します。

  2. b = a.copy():浅いコピー、aおよびb2つの隔離対象となりますが、その内容は同じ参照を共有します

    「b = a.copy()」の例:「a」は「{1:L}」を指し、「b」は「{1:M}」を指し、「L」と「M」はどちらも「[ 1、2、3] '。

  3. b = copy.deepcopy(a):ディープコピー、aおよびbの構造とコンテンツは完全に分離されます。

    「b = copy.deepcopy(a)」の例:「a」は「{1:L}」を指し、「L」は「[1、2、3]」を指します。 「b」は「{1:M}」を指し、「M」は「[1、2、3]」の別のインスタンスを指します。


いい答えですが、最初の文の文法エラーを修正することを検討してください。でL再度使用しない理由はありませんb。そうすることで、例が簡略化されます。
トムラッセル

@kennytm:実際、最初の2つの例の違いは何ですか?同じ結果が得られますが、内部実装がわずかに異なりますが、何が問題なのでしょうか。
JavaSa 2018年

@TomRussell:または、誰でも、この質問はかなり古いので、私の説明の質問はすべての人を対象としています
JavaSa

@JavaSaたとえば、あなたがそうするかどうかは重要ですb[1][0] = 5。場合はb浅いコピーである、あなただけ変更しましたa[1][0]
トムラッセル

2
素晴らしい説明...本当に私の一日を救った!ありがとう...これは、リスト、str、およびその他のPythonのデータ型に適用できますか?
Bhuro

38

それはディープコピーやシャローコピーの問題ではなく、あなたがしていることのどれもディープコピーではありません。

ここに:

>>> new = original 

オリジナルによって参照されるリスト/辞書への新しい参照を作成しています。

ここにいる間:

>>> new = original.copy()
>>> # or
>>> new = list(original) # dict(original)

元のコンテナに含まれているオブジェクトの参照のコピーで満たされた新しいリスト/辞書を作成しています。


31

この例を見てみましょう:

original = dict(a=1, b=2, c=dict(d=4, e=5))
new = original.copy()

次に、「浅い」(最初の)レベルの値を変更します。

new['a'] = 10
# new = {'a': 10, 'b': 2, 'c': {'d': 4, 'e': 5}}
# original = {'a': 1, 'b': 2, 'c': {'d': 4, 'e': 5}}
# no change in original, since ['a'] is an immutable integer

次に、値を1レベル深く変更します。

new['c']['d'] = 40
# new = {'a': 10, 'b': 2, 'c': {'d': 40, 'e': 5}}
# original = {'a': 1, 'b': 2, 'c': {'d': 40, 'e': 5}}
# new['c'] points to the same original['d'] mutable dictionary, so it will be changed

8
no change in original, since ['a'] is an immutable integerこの。それは実際に尋ねられた質問に答えます。
CivFan 2015

8

kennytmの答えに追加します。浅いコピーparent.copy()を実行すると、同じキーで新しいディクショナリが作成されますが、値はコピーされません。参照されます。parent_copyに新しい値を追加しても、parent_copyは新しいディクショナリであるため、親には影響しません。参照ではありません。

parent = {1: [1,2,3]}
parent_copy = parent.copy()
parent_reference = parent

print id(parent),id(parent_copy),id(parent_reference)
#140690938288400 140690938290536 140690938288400

print id(parent[1]),id(parent_copy[1]),id(parent_reference[1])
#140690938137128 140690938137128 140690938137128

parent_copy[1].append(4)
parent_copy[2] = ['new']

print parent, parent_copy, parent_reference
#{1: [1, 2, 3, 4]} {1: [1, 2, 3, 4], 2: ['new']} {1: [1, 2, 3, 4]}

parent [1]parent_copy [1]のhash(id)値は同一であり、id [140690938288400]に格納されているparent [1]parent_copy [1]の [1,2,3]を意味します。

しかし、parentparent_copyのハッシュは異なります。つまり、それらは異なる辞書であり、parent_copyは、parentの値を参照する値を持つ新しい辞書です。


5

「新」と「オリジナル」..あなたがそれらの1つだけ更新できる理由です、異なるdictsているアイテムは浅いコピーではなく、辞書そのものです。


2

内容は浅いコピーです。

したがって、オリジナルdictlistやが含まれている場合dictionary、オリジナルまたはその浅いコピーで一方を変更すると、もう一方listでも(またはdict)が変更されます。


1

2番目の部分では、 new = original.copy()

.copy=は違うものです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.