¿Por qué la actualización del diccionario de copia "superficial" no actualiza el diccionario "original"? [duplicar]
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?
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:
b = a
: Asignación de referencia, Marcaa
yb
apunta al mismo objeto.b = a.copy()
: Copia superficiala
yb
se convertirán en dos objetos aislados, pero sus contenidos aún comparten la misma referencia.b = copy.deepcopy(a)
: Copia profunda,a
yb
la estructura y el contenido quedan completamente aislados.
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