¿Alguien puede explicarme esto? Esto no tiene ningún sentido para mí.
Copio un diccionario en otro y edito el segundo y ambos cambian. ¿Por qué está pasando esto?
>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2
{'key2': 'value2', 'key1': 'value1'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}
python
python-3.x
dictionary
reference
MadSc13ntist
fuente
fuente
dict1
ydict2
señalar el mismo dict.Respuestas:
Python nunca copia implícitamente objetos. Cuando establece
dict2 = dict1
, hace que se refieran al mismo objeto dict exacto, por lo que cuando lo muta, todas las referencias se refieren al objeto en su estado actual.Si desea copiar el dict (lo cual es raro), debe hacerlo explícitamente con
o
fuente
dir(1)
para ver eso), pero se copian implícitamente.int
,float
y lasbool
instancias son objetos reales de Python, y b) los objetos de estos tipos no se copian implícitamente cuando los pasa, ni a un nivel semántico de Python con seguridad, ni siquiera como un detalle de implementación en CPython.copy.deepcopy()
lugar dedict()
odict.copy()
. La respuesta concisa de Imran está en el lado correcto de la cordura, a diferencia de esta respuesta.Cuando asigna
dict2 = dict1
, no está haciendo una copia dedict1
, resulta endict2
ser solo otro nombre paradict1
.Para copiar los tipos mutables como diccionarios, use
copy
/deepcopy
delcopy
módulo.fuente
Mientras
dict.copy()
, ydict(dict1)
genera una copia, sólo son poco profundas copias. Si desea una copia profunda ,copy.deepcopy(dict1)
se requiere. Un ejemplo:Con respecto a las copias superficiales y profundas, de los documentos del módulo Python
copy
:fuente
w=copy.deepcopy(x)
es la línea clave.dict2 = dict1
ydict2 = copy.deepcopy(dict1)
?En python 3.5+ hay una manera más fácil de lograr una copia superficial utilizando el operador de desempaquetado **. Definido por Pep 448 .
** desempaqueta el diccionario en un nuevo diccionario que luego se asigna a dict2.
También podemos confirmar que cada diccionario tiene una identificación distinta.
Si se necesita una copia profunda, copy.deepcopy () sigue siendo el camino a seguir.
fuente
dict2 = {**dict1, 'key3':'value3'}
Las mejores y más fáciles formas de crear una copia de un dict en Python 2.7 y 3 son ...
Para crear una copia del diccionario simple (de un solo nivel):
1. Usando el método dict () , en lugar de generar una referencia que apunte al dict existente.
2. Usando el método incorporado update () del diccionario python.
Para crear una copia de un diccionario anidado o complejo:
Utilice el módulo de copia incorporado , que proporciona operaciones genéricas de copia superficial y profunda. Este módulo está presente en Python 2.7 y 3. *
fuente
dict()
crea una copia superficial, no una copia profunda. Lo que significa que si tiene un anidadodict
, el exteriordict
será una copia, pero el dict interno será una referencia al dict interno original.También puede crear un nuevo diccionario con una comprensión del diccionario. Esto evita importar la copia.
Por supuesto, en python> = 2.7 puedes hacer:
Pero para la compatibilidad con versiones anteriores, el método superior es mejor.
fuente
d2 = dict.copy(d1)
tampoco requiere ninguna importación.d2 = d1.copy()
dict.items
ya devuelve un par clave / valor iterable. Así que solo puedes usardict(mydict.items())
(también puedes usardict(mydict)
). Puede ser útil tener la comprensión si desea filtrar las entradas.Además de las otras soluciones proporcionadas, puede utilizar
**
para integrar el diccionario en un diccionario vacío, por ejemplo,shallow_copy_of_other_dict = {**other_dict}
.Ahora tendrá una copia "superficial" de
other_dict
.Aplicado a tu ejemplo:
Puntero: diferencia entre copias superficiales y profundas
fuente
Las declaraciones de asignación en Python no copian objetos, crean enlaces entre un objetivo y un objeto.
entonces,
dict2 = dict1
resulta otro enlace entredict2
y el objeto al que sedict1
refieren.si quieres copiar un dict, puedes usar el
copy module
. El módulo de copia tiene dos interfaces:La diferencia entre copia superficial y profunda solo es relevante para objetos compuestos (objetos que contienen otros objetos, como listas o instancias de clase):
Una copia superficial construye un nuevo objeto compuesto y luego (en la medida de lo posible) inserta referencias en él a los objetos encontrados en el original.
Una copia profunda construye un nuevo objeto compuesto y luego, recursivamente, inserta copias de los objetos encontrados en el original.
Por ejemplo, en python 2.7.9:
y el resultado es:
fuente
Puede copiar y editar la copia recién construida de una vez llamando al
dict
constructor con argumentos de palabras clave adicionales:fuente
Esto también me confundió, inicialmente, porque venía de un fondo C.
En C, una variable es una ubicación en la memoria con un tipo definido. La asignación a una variable copia los datos en la ubicación de memoria de la variable.
Pero en Python, las variables actúan más como punteros a los objetos. Entonces, asignar una variable a otra no hace una copia, solo hace que el nombre de la variable apunte al mismo objeto.
fuente
Cada variable en Python (cosas como
dict1
ostr
o__builtins__
es un puntero a algún "objeto" platónico oculto dentro de la máquina.Si configura
dict1 = dict2
, solo apuntadict1
al mismo objeto (o ubicación de memoria, o cualquier analogía que desee) comodict2
. Ahora, el objeto al que hace referenciadict1
es el mismo objeto al que hace referenciadict2
.Puede verificar:
dict1 is dict2
debería serTrue
. Además,id(dict1)
debe ser lo mismo queid(dict2)
.Tu quieres
dict1 = copy(dict2)
, odict1 = deepcopy(dict2)
.La diferencia entre
copy
ydeepcopy
?deepcopy
se asegurará de que los elementos dedict2
(¿lo señaló en una lista?) también sean copias.No uso
deepcopy
mucho; por lo general, es una mala práctica escribir código que lo necesita (en mi opinión).fuente
dict1
es un símbolo que hace referencia a un objeto de diccionario subyacente. Asignardict1
adict2
simplemente asigna la misma referencia. Cambiar el valor de una clave a través deldict2
símbolo cambia el objeto subyacente, lo que también afectadict1
. Esto es confuso.Es mucho más fácil razonar sobre valores inmutables que referencias, así que haga copias siempre que sea posible:
Esto es sintácticamente lo mismo que:
fuente
dict2 = dict1
No copia el diccionario. Simplemente le da al programador una segunda forma (dict2
) para referirse al mismo diccionario.fuente
Hay muchas formas de copiar objetos Dict, simplemente uso
fuente
dict_2 = dict_1.copy()
Es mucho más eficiente y lógico.Como otros han explicado, el incorporado
dict
no hace lo que quieres. Pero en Python2 (y probablemente también en el 3) puedes crear fácilmente unaValueDict
clase con la que copiar=
para que puedas estar seguro de que el original no cambiará.Consulte el patrón de modificación de lvalue discutido aquí: Python 2.7 - sintaxis limpia para la modificación de lvalue . La observación clave es eso
str
yint
comportarse como valores en Python (a pesar de que en realidad son objetos inmutables bajo el capó). Mientras observa eso, tenga en cuenta también que nada es mágicamente especial sobrestr
oint
.dict
puede usarse de la misma manera, y puedo pensar en muchos casos en los queValueDict
tiene sentido.fuente
el siguiente código, que se encuentra en los dictados que sigue la sintaxis json más de 3 veces más rápido que la copia profunda
fuente
Me encontré con un comportamiento peculiar al intentar copiar en profundidad la propiedad del diccionario de la clase sin asignarla a la variable
new = copy.deepcopy(my_class.a)
no funciona, es decir, modificarnew
modificamy_class.a
pero si lo hace
old = my_class.a
ynew = copy.deepcopy(old)
funciona perfectamente, es decir, modificarnew
no afectamy_class.a
No estoy seguro de por qué sucede esto, ¡pero espero que ayude a ahorrar algunas horas! :)
fuente
my_class.a
?porque, dict2 = dict1, dict2 contiene la referencia a dict1. Tanto dict1 como dict2 apuntan a la misma ubicación en la memoria. Este es solo un caso normal mientras se trabaja con objetos mutables en python. Cuando trabaje con objetos mutables en python, debe tener cuidado ya que es difícil de depurar. Tal como el siguiente ejemplo.
La intención de este ejemplo es obtener todos los ID de usuario, incluidos los ID bloqueados. Eso lo obtuvimos de la variable ids pero también actualizamos el valor de my_users sin querer. cuando extendió los identificadores con blocks_ids, my_users se actualizaron porque los identificadores se refieren a my_users .
fuente
Copiar usando un bucle for:
fuente
deepcopy
, que está construido expresamente para este propósito?Puedes usar directamente:
donde objeto dict2 es una copia independiente de dict1, por lo que puede modificar dict2 sin afectar a dict1.
Esto funciona para cualquier tipo de objeto.
fuente
__repr__
para ser reconstruido por eval, ni la clase del objeto puede estar en el alcance actual para ser llamado. Incluso si se apega a los tipos incorporados, esto fallará si el mismo objeto se almacena en varias claves, yadict2
que entonces tendría dos objetos separados. Un diccionario autorreferencial, donde sedict1
contiene, contendrá en su lugarEllipsis
. Sería mejor usarlodict1.copy()