¿Por qué la actualización del diccionario de copia "superficial" no actualiza el diccionario "original"? [duplicar]

Resuelto user225312 asked hace 13 años • 7 respuestas

Mientras lee la documentación de dict.copy(), dice que hace una copia superficial del diccionario. Lo mismo ocurre con el libro que estoy siguiendo (Referencia de Python de Beazley), que dice:

El método m.copy() hace una copia superficial de los elementos contenidos en un objeto de mapeo y los coloca en un nuevo objeto de mapeo.

Considera esto:

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

Entonces asumí que esto actualizaría el valor de original(y agregaría 'c': 3) también ya que estaba haciendo una copia superficial. Like si lo haces para una lista:

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

Esto funciona como se esperaba.

Dado que ambas son copias superficiales, ¿por qué dict.copy()no funciona como esperaba? ¿O mi comprensión de la copia superficial y profunda es errónea?

user225312 avatar Oct 20 '10 13:10 user225312
Aceptado

Por "copia superficial" significa que el contenido del diccionario no se copia por valor, sino que simplemente se crea una nueva referencia.

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

Por el contrario, una copia profunda copiará todo el contenido por valor.

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

Entonces:

  1. b = a: Asignación de referencia, Marca ay bapunta al mismo objeto.

    Ilustración de 'a = b': 'a' y 'b' apuntan a '{1: L}', 'L' apunta a '[1, 2, 3]'.

  2. b = a.copy(): Copia superficial ay bse convertirán en dos objetos aislados, pero sus contenidos aún comparten la misma referencia.

    Ilustración de 'b = a.copy()': 'a' apunta a '{1: L}', 'b' apunta a '{1: M}', 'L' y 'M' apuntan a '[ 1, 2, 3]'.

  3. b = copy.deepcopy(a): Copia profunda, ay bla estructura y el contenido quedan completamente aislados.

    Ilustración de 'b = copy.deepcopy(a)': 'a' apunta a '{1: L}', 'L' apunta a '[1, 2, 3]';  'b' apunta a '{1: M}', 'M' apunta a una instancia diferente de '[1, 2, 3]'.

kennytm avatar Oct 20 '2010 06:10 kennytm

Tome este ejemplo:

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

Ahora cambiemos un valor en el (primer) nivel 'superficial':

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

Ahora cambiemos un valor un nivel más profundo:

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
eumiro avatar Oct 20 '2010 07:10 eumiro