import copy
a = "deepak"
b = 1, 2, 3, 4
c = [1, 2, 3, 4]
d = {1: 10, 2: 20, 3: 30}
a1 = copy.copy(a)
b1 = copy.copy(b)
c1 = copy.copy(c)
d1 = copy.copy(d)
print("immutable - id(a)==id(a1)", id(a) == id(a1))
print("immutable - id(b)==id(b1)", id(b) == id(b1))
print("mutable - id(c)==id(c1)", id(c) == id(c1))
print("mutable - id(d)==id(d1)", id(d) == id(d1))
Obtengo los siguientes resultados:
immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) False
mutable - id(d)==id(d1) False
Si realizo una copia profunda:
a1 = copy.deepcopy(a)
b1 = copy.deepcopy(b)
c1 = copy.deepcopy(c)
d1 = copy.deepcopy(d)
Los resultados son los mismos:
immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) False
mutable - id(d)==id(d1) False
Si trabajo en operaciones de asignación:
a1 = a
b1 = b
c1 = c
d1 = d
entonces los resultados son:
immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) True
mutable - id(d)==id(d1) True
¿Alguien puede explicar qué hace exactamente la diferencia entre las copias? ¿Es algo relacionado con objetos mutables e inmutables? Si es así, ¿me lo puedes explicar?
fuente
list_=[[1,2],[3,4]] newlist = list_.copy() list_[0]=[7,8] print(list_) print(newlist)
Lanewlist
visualización fija[[1, 2], [3, 4]]
. Perolist_[0]
es una lista que es mutable.list_[0]
es mutable, pero no lo está mutando / modificando. Probarlist_[0].append(9)
o en sulist_[0][0] = 7
lugar.Para los objetos inmutables, no hay necesidad de copiar porque los datos nunca cambiarán, por lo que Python usa los mismos datos; Los ID son siempre iguales. Para objetos mutables, dado que pueden cambiar potencialmente, la copia [superficial] crea un nuevo objeto.
La copia profunda está relacionada con estructuras anidadas. Si tiene una lista de listas, entonces realice
copies
una copia profunda de las listas anidadas, por lo que es una copia recursiva. Con solo copiar, tiene una nueva lista externa, pero las listas internas son referencias.La asignación no se copia. Simplemente establece la referencia a los datos antiguos. Por lo tanto, necesita copiar para crear una nueva lista con el mismo contenido.
fuente
With just copy, you have a new outer list but inner lists are references.
Para las listas internas, ¿estaría el copiado influenciado por el original? Creo una lista de listas comolist_=[[1,2],[3,4]] newlist = list_.copy() list_[0]=[7,8]
y lanewlist
sigue siendo la misma, ¿la lista interna son referencias?list_[0][0] = 7
Para los objetos inmutables, crear una copia no tiene mucho sentido ya que no van a cambiar. Para objetos mutables
assignment
,copy
y sedeepcopy
comporta de manera diferente. Hablemos de cada uno de ellos con ejemplos.Una operación de asignación simplemente asigna la referencia de origen a destino, por ejemplo:
Ahora
i
yj
técnicamente se refiere a la misma lista. Ambosi
yj
tienen la misma dirección de memoria. Cualquier actualización a cualquiera de ellos se reflejará en el otro. p.ej:Por otro lado
copy
ydeepcopy
crea una nueva copia de variable. Por lo tanto, ahora los cambios en la variable original no se reflejarán en la variable de copia y viceversa. Sin embargocopy(shallow copy)
, no crea una copia de objetos anidados, sino que simplemente copia la referencia de los objetos anidados. Deepcopy copia todos los objetos anidados recursivamente.Algunos ejemplos para demostrar el comportamiento de
copy
ydeepcopy
:Ejemplo de lista plana usando
copy
:Ejemplo de lista anidada usando
copy
:Ejemplo de lista plana usando
deepcopy
:Ejemplo de lista anidada usando
deepcopy
:fuente
Veamos en un ejemplo gráfico cómo se ejecuta el siguiente código:
fuente
a, b, c, d, a1, b1, c1 y d1 son referencias a objetos en la memoria, que se identifican de manera única por sus identificadores.
Una operación de asignación toma una referencia al objeto en la memoria y asigna esa referencia a un nuevo nombre.
c=[1,2,3,4]
es una asignación que crea un nuevo objeto de lista que contiene esos cuatro enteros y asigna la referencia a ese objetoc
.c1=c
es una asignación que toma la misma referencia al mismo objeto y se la asigna ac1
. Dado que la lista es mutable, cualquier cosa que le suceda a esa lista será visible independientemente de si accede a ellac
oc1
porque ambos hacen referencia al mismo objeto.c1=copy.copy(c)
es una "copia superficial" que crea una nueva lista y asigna la referencia a la nueva listac1
.c
Todavía apunta a la lista original. Por lo tanto, si modifica la lista enc1
, la lista a la que sec
refiere no cambiará.El concepto de copia es irrelevante para objetos inmutables como enteros y cadenas. Como no puede modificar esos objetos, nunca es necesario tener dos copias del mismo valor en la memoria en diferentes ubicaciones. Por lo tanto, los enteros y las cadenas, y algunos otros objetos a los que no se aplica el concepto de copia, simplemente se reasignan. Es por eso que sus ejemplos con
a
yb
resultan en identificaciones idénticasc1=copy.deepcopy(c)
es una "copia profunda", pero en este ejemplo funciona igual que una copia superficial. Las copias profundas difieren de las copias superficiales en que las copias superficiales harán una nueva copia del objeto en sí, pero las referencias dentro de ese objeto no se copiarán. En su ejemplo, su lista solo tiene enteros dentro (que son inmutables) y, como se discutió anteriormente, no es necesario copiarlos. Por lo tanto, la parte "profunda" de la copia profunda no se aplica. Sin embargo, considere esta lista más compleja:e = [[1, 2],[4, 5, 6],[7, 8, 9]]
Esta es una lista que contiene otras listas (también podría describirla como una matriz bidimensional).
Si ejecuta una "copia superficial"
e
, copiándolae1
, encontrará que la identificación de la lista cambia, pero cada copia de la lista contiene referencias a las mismas tres listas: las listas con números enteros dentro. Eso significa que si tuvieras que hacere[0].append(3)
, entoncese
sería[[1, 2, 3],[4, 5, 6],[7, 8, 9]]
. Peroe1
también lo sería[[1, 2, 3],[4, 5, 6],[7, 8, 9]]
. Por otro lado, si posteriormente lo hicierase.append([10, 11, 12])
,e
sería[[1, 2, 3],[4, 5, 6],[7, 8, 9],[10, 11, 12]]
. Peroe1
aún lo sería[[1, 2, 3],[4, 5, 6],[7, 8, 9]]
. Esto se debe a que las listas externas son objetos separados que inicialmente contienen tres referencias a tres listas internas. Si modifica las listas internas, puede ver esos cambios sin importar si los está viendo a través de una copia u otra. Pero si modifica una de las listas externas como se indicó anteriormente, entoncese
contiene tres referencias a las tres listas originales más una referencia más a una nueva lista. Ye1
todavía solo contiene las tres referencias originales.Una 'copia profunda' no solo duplicaría la lista externa, sino que también iría dentro de las listas y duplicaría las listas internas, de modo que los dos objetos resultantes no contengan ninguna de las mismas referencias (en lo que respecta a los objetos mutables) . Si las listas internas tuvieran más listas (u otros objetos como diccionarios) dentro de ellas, también se duplicarían. Esa es la parte 'profunda' de la 'copia profunda'.
fuente
En python, cuando asignamos objetos como list, tuples, dict, etc. a otro objeto, generalmente con un signo '=', python crea copias por referencia . Es decir, digamos que tenemos una lista de listas como esta:
y asignamos otra lista a esta lista como:
entonces si imprimimos list2 en la terminal de Python obtendremos esto:
Tanto list1 como list2 apuntan a la misma ubicación de memoria, cualquier cambio en cualquiera de ellas dará como resultado cambios visibles en ambos objetos, es decir, ambos objetos apuntan a la misma ubicación de memoria. Si cambiamos list1 así:
entonces tanto list1 como list2 serán:
Ahora llegando a la copia superficial , cuando dos objetos se copian mediante una copia superficial, el objeto secundario de ambos objetos primarios se refiere a la misma ubicación de memoria, pero cualquier cambio nuevo en cualquiera de los objetos copiados será independiente entre sí. Comprendamos esto con un pequeño ejemplo. Supongamos que tenemos este pequeño fragmento de código:
aviso, list2 no se ve afectado, pero si hacemos cambios en objetos secundarios como:
entonces la lista1 y la lista2 obtendrán cambios:
Ahora, la copia profunda ayuda a crear objetos completamente aislados entre sí. Si se copian dos objetos a través de Deep Copy, tanto el padre como el hijo apuntarán a una ubicación de memoria diferente. Ejemplo:
aviso, list2 no se ve afectado, pero si hacemos cambios en objetos secundarios como:
entonces list2 no se verá afectado ya que todos los objetos secundarios y principales apuntan a una ubicación de memoria diferente:
Espero eso ayude.
fuente
El siguiente código muestra la diferencia entre la asignación, copia superficial utilizando el método de copia, copia superficial utilizando el (corte) [:] y la copia profunda. El siguiente ejemplo utiliza listas anidadas al hacer las diferencias más evidentes.
fuente
El GIST a tomar es el siguiente: tratar con listas poco profundas (sin sublistas, solo elementos individuales) usando "asignación normal" aumenta un "efecto secundario" cuando crea una lista superficial y luego crea una copia de esta lista usando "asignación normal" . Este "efecto secundario" se produce cuando cambia cualquier elemento de la lista de copias creado, porque cambiará automáticamente los mismos elementos de la lista original. Eso es
copy
útil, ya que no cambiará los elementos de la lista original al cambiar los elementos de copia.Por otro lado, también
copy
tiene un "efecto secundario", cuando tiene una lista que contiene listas (sub_lists) y ladeepcopy
resuelve. Por ejemplo, si crea una lista grande que tiene listas anidadas (sub_lists) y crea una copia de esta lista grande (la lista original). El "efecto secundario" surgiría cuando modifique las sub_listas de la lista de copias, lo que modificaría automáticamente las sub_listas de la lista grande. A veces (en algunos proyectos) desea mantener la lista grande (su lista original) tal como está sin modificaciones, y todo lo que desea es hacer una copia de sus elementos (sub_lists). Para eso, su solución es usar eldeepcopy
que se encargará de este "efecto secundario" y hará una copia sin modificar el contenido original.Los diferentes comportamientos
copy
ydeep copy
operaciones se refieren solo a objetos compuestos (es decir, objetos que contienen otros objetos como listas).Estas son las diferencias ilustradas en este ejemplo de código simple:
primero
Vamos a ver cómo se
copy
comporta (superficial), creando una lista original y una copia de esta lista:Ahora, ejecutemos algunas
print
pruebas y veamos cómo se comporta la lista original en comparación con su lista de copias:original_list y copy_list tienen diferentes direcciones
Los elementos de original_list y copy_list tienen las mismas direcciones
Los subelementos de original_list y copy_list tienen las mismas direcciones
la modificación de elementos original_list NO modifica elementos copy_list
modificar elementos copy_list NO modifica elementos original_list
modificar sub_elementos original_list modificar automáticamente sub_elementos copy_list
modificando copy_list sub_elements modifica automáticamente original_list sub_elements
Segundo
Vamos a ver cómo se
deepcopy
comporta, haciendo lo mismo que hicimos con nosotroscopy
(creando una lista original y una copia de esta lista):Ahora, ejecutemos algunas
print
pruebas y veamos cómo se comporta la lista original en comparación con su lista de copias:original_list y copy_list tienen diferentes direcciones
Los elementos de original_list y copy_list tienen las mismas direcciones
Los subelementos de original_list y copy_list tienen diferentes direcciones
la modificación de elementos original_list NO modifica elementos copy_list
modificar elementos copy_list NO modifica elementos original_list
modificar sub_elementos original_list NO modifica sub_elementos copy_list
modificando copy_list sub_elements NO modifica original_list sub_elements
fuente
No estoy seguro de si se mencionó anteriormente o no, pero es muy importante entender que .copy () crea una referencia al objeto original. Si cambia el objeto copiado, cambia el objeto original. .deepcopy () crea un nuevo objeto y hace una copia real del objeto original en uno nuevo. Cambiar un nuevo objeto copiado en profundidad no afecta al objeto original.
Y sí, .deepcopy () copia el objeto original de forma recursiva, mientras que .copy () crea un objeto de referencia a los datos de primer nivel del objeto original.
Por lo tanto, la diferencia de copia / referencia entre .copy () y .deepcopy () es significativa.
fuente
La copia profunda está relacionada con estructuras anidadas. Si tiene una lista de listas, entonces la copia profunda también copia las listas anidadas, por lo que es una copia recursiva. Con solo copiar, tiene una nueva lista externa, pero las listas internas son referencias. La asignación no se copia. Para ex
Salida
[[0, 1, 2, 3, 3], 4, 5] [[0, 1, 2, 3, 3], 4, 5, 3] Método de copia copia el contenido de la lista externa a la nueva lista pero la lista interna es sigue siendo igual para ambas listas, por lo que si realiza cambios en la lista interna de cualquier lista, afectará a ambas.
Pero si usa la copia profunda, también creará una nueva instancia para la lista interna.
Salida
[0, 1, 2, 3] [[0, 1, 2, 3, 3], 4, 5, 3]
fuente
fuente
a
no es una copia profunda delst
!