usuario225312
Mientras leía la documentación de dict.copy()
, dice que hace una copia superficial del diccionario. Lo mismo ocurre con el libro que estoy siguiendo (Beazley’s Python Reference), 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}
Así que asumí que esto actualizaría el valor de original
(y agregue ‘c’: 3) también porque estaba haciendo una copia superficial. Like si lo haces por 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 ambos son copias superficiales, ¿por qué es que el dict.copy()
no funciona como esperaba? ¿O mi comprensión de la copia superficial frente a la profunda es defectuosa?
kennytm
Por “copia superficial” se entiende la contenido del diccionario no se copia por valor, sino simplemente creando 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á todos los contenidos 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 superficial,a
yb
se convertirán en dos objetos aislados, pero sus contenidos seguirán compartiendo la misma referencia -
b = copy.deepcopy(a)
: copia profunda,a
yb
La estructura y el contenido de quedan completamente aislados.
-
Buena respuesta, pero podría considerar corregir el error gramatical en su primera oración. Y no hay razón para no usar
L
de nuevo enb
. Hacerlo simplificaría el ejemplo.–Tom Russell
27 de octubre de 2017 a las 4:47
-
@kennytm: ¿Cuál es la diferencia entre los dos primeros ejemplos, de hecho? Obtiene el mismo resultado, pero una implementación interna ligeramente diferente, pero ¿qué importa?
– Java Sa
20 de enero de 2018 a las 11:53
-
@JavaSa
a[1] = {}
afectaráb
en el primer ejemplo, y no afectaráb
en el segundo ejemplo.– kennytm
22 de enero de 2018 a las 18:08
-
Gran explicación,… ¡realmente me salvó el día! Gracias … ¿Se puede aplicar esto mismo a la lista, str y otros tipos de datos de python?
– Bhuro
19 de febrero de 2018 a las 13:38
-
@Sheldore
dic_a
ydic_b
están haciendo referencia al mismo diccionario cuandodic_b = dic_a
. Las cadenas en el diccionario son inmutables pero eso es irrelevante, porquedic_b['A'] = 'Adam'
muta el propio diccionario.– kennytm
20 de septiembre de 2020 a las 17:54
Toma este ejemplo:
original = dict(a=1, b=2, c=dict(d=4, e=5))
new = original.copy()
Ahora cambiemos un valor en el nivel ‘superficial’ (primero):
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
-
no change in original, since ['a'] is an immutable integer
Este. En realidad responde a la pregunta formulada.– CivFan
14 de abril de 2015 a las 18:08
No es una cuestión de copia profunda o copia superficial, nada de lo que estás haciendo es una copia profunda.
Aquí:
>>> new = original
está creando una nueva referencia a la lista/dictado al que hace referencia el original.
mientras aquí:
>>> new = original.copy()
>>> # or
>>> new = list(original) # dict(original)
está creando una nueva lista/dictado que se completa con una copia de las referencias de los objetos contenidos en el contenedor original.
-
Cierto, hasta donde llega… pero no va lo suficientemente lejos como para responder la pregunta OP sobre lo superficial frente a lo profundo.
– MarkHu
11 de febrero de 2021 a las 2:02
Vkreddy
Agregando a la respuesta de kennytm. Cuando haces una copia superficial padre.copia() se crea un nuevo diccionario con las mismas claves, pero los valores no se copian, se hace referencia a ellos. Si agrega un nuevo valor a parent_copy no tendrá efecto padre porque parent_copy es un nuevo diccionario no de referencia.
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]}
El valor hash (id) de padre[1], parent_copy[1] son idénticos lo que implica [1,2,3] de padre[1] y parent_copy[1] almacenado en id 140690938288400.
Pero hash de padre y parent_copy son diferentes lo que implica que son diferentes diccionarios y parent_copy es un nuevo diccionario que tiene valores de referencia a valores de padre
“nuevo” y “original” son dictados diferentes, es por eso que puede actualizar solo uno de ellos. elementos son copias superficiales, no el dictado en sí.
Esteban Rauch
En tu segunda parte, deberías usar new = original.copy()
.copy
y =
son cosas diferentes.
Cazador de la selva
Contenido se copian superficialmente.
Entonces si el original dict
contiene una list
u otro dictionary
modificándolos en el original o en su copia superficial los modificará (los list
o el dict
) en el otro.
Pintoresco que no explican “superficial”. Conocimiento interno, guiño. Solo el dictado y las claves son una copia, mientras que los dictados anidados dentro de ese primer nivel son referencias, no se pueden eliminar en un bucle, por ejemplo. Por lo tanto, dict.copy() de Python en ese caso no es útil ni intuitivo. Gracias por tu pregunta.
– gseattle
9 de junio de 2017 a las 10:34
“Dado que ambas son copias superficiales”, ese es el problema aquí. el segundo ejemplo no es una copia, superficial o no.
– Karl Knechtel
hace 2 días