Inzicht in dict.copy() – oppervlakkig of diep?

Tijdens het lezen van de documentatie voor dict.copy(), zegt het dat het een oppervlakkige kopie van het woordenboek maakt. Hetzelfde geldt voor het boek dat ik volg (Beazley’s Python Reference), dat zegt:

De methode m.copy() maakt een ondiepe
kopie van de items in a
mapping object en plaatst ze in a
nieuw kaartobject.

Overweeg dit:

>>> 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}

Dus ik nam aan dat dit de waarde van originalzou bijwerken (en ‘c’: 3) zou toevoegen, ook omdat ik een ondiepe kopie aan het maken was. Like als je het voor een lijst doet:

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

Dit werkt zoals verwacht.

Omdat beide oppervlakkige kopieën zijn, waarom werkt de dict.copy()niet zoals ik verwacht? Of is mijn begrip van oppervlakkig versus diep kopiëren gebrekkig?


Antwoord 1, autoriteit 100%

Met “ondiep kopiëren” betekent dit dat de inhoudvan het woordenboek niet op waarde wordt gekopieerd, maar dat er alleen een nieuwe referentie wordt gemaakt.

>>> 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]})

Een diepe kopie daarentegen kopieert alle inhoud op waarde.

>>> 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]})

Dus:

  1. b = a: Referentietoewijzing, Make aen bverwijst naar hetzelfde object.

  2. b = a.copy(): Ondiep kopiëren, aen bworden twee geïsoleerde objecten, maar hun inhoud deel nog steeds dezelfde referentie

  3. b = copy.deepcopy(a): Deep copying, de structuur en inhoud van aen braken volledig geïsoleerd .


Antwoord 2, autoriteit 3%

Het is geen kwestie van diep kopiëren of oppervlakkig kopiëren, niets van wat u doet is diep kopiëren.

Hier:

>>> new = original 

je maakt een nieuwe verwijzing naar de lijst/dictaat waarnaar in het origineel wordt verwezen.

terwijl hier:

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

je maakt een nieuwe lijst/dictaat die is gevuld met een kopie van de referenties van objecten in de originele container.


Antwoord 3, autoriteit 3%

Neem dit voorbeeld:

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

Laten we nu een waarde wijzigen in het ‘ondiepe’ (eerste) niveau:

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

Laten we nu een waarde een niveau dieper wijzigen:

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

Antwoord 4

Toevoegen aan het antwoord van kennytm. Wanneer u parent.copy()een oppervlakkige kopie maakt, wordt er een nieuw woordenboek gemaakt met dezelfde sleutels, maar de waarden worden niet gekopieerd, er wordt naar verwezen. Als u een nieuwe waarde toevoegt parent_copyheeft geen effect op parentomdat parent_copyis een nieuw woordenboek, geen referentie.

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]}

De hash(id)-waarde van parent[1], parent_copy[1]zijn identiek en impliceert [1,2,3] van parent[1]en parent_copy[1]opgeslagen op id 140690938288400 .

Maar hash van parenten parent_copyzijn verschillend, wat impliceert
Het zijn verschillende woordenboeken en parent_copyis een nieuw woordenboek met waarden die verwijzen naar waarden van parent


Antwoord 5

“nieuw” en “origineel” zijn verschillende dictaten, daarom kunt u er maar één bijwerken.. De itemszijn oppervlakkig gekopieerd, niet het dictaat zelf.


Antwoord 6

Inhoudis oppervlakkig gekopieerd.

Dus als het originele dicteen listof een ander dictionarybevat, zal het wijzigen van een van deze in het origineel of de ondiepe kopie deze wijzigen ( de listof het dict) in de andere.


Antwoord 7

In je tweede deel moet je new = original.copy()

. gebruiken

.copyen =zijn verschillende dingen.

Other episodes