¿Cómo copiar en profundidad una lista?

Resuelto Shen asked hace 11 años • 10 respuestas

Después E0_copy = list(E0), supongo E0_copyque es una copia profunda de E0ya que id(E0)no es igual a id(E0_copy). Luego modifico E0_copyen el bucle, pero ¿por qué E0no es lo mismo después?

E0 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
for k in range(3):
    E0_copy = list(E0)
    E0_copy[k][k] = 0
    #print(E0_copy)
print E0  # -> [[0, 2, 3], [4, 0, 6], [7, 8, 0]]
Shen avatar Jul 26 '13 12:07 Shen
Aceptado

E0_copyNo es una copia profunda. No haces una copia profunda usando list(). (Ambos list(...)y testList[:]son copias superficiales, así como también testList.copy().)

Se utiliza copy.deepcopy(...)para copiar en profundidad una lista.

copy.deepcopy(x[, memo])

Devuelve una copia profunda de x .

Vea el siguiente fragmento:

>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = list(a)
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0][1] = 10
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b   # b changes too -> Not a deepcopy.
[[1, 10, 3], [4, 5, 6]]

Ahora mira la deepcopyoperación .

>>> import copy
>>> b = copy.deepcopy(a)
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b
[[1, 10, 3], [4, 5, 6]]
>>> a[0][1] = 9
>>> a
[[1, 9, 3], [4, 5, 6]]
>>> b    # b doesn't change -> Deep Copy
[[1, 10, 3], [4, 5, 6]]

Para explicarlo, list(...)no hace copias recursivas de los objetos internos. Solo hace una copia de la lista más externa, sin dejar de hacer referencia a las mismas listas internas, por lo tanto, cuando muta las listas internas, el cambio se refleja tanto en la lista original como en la copia superficial. Puede ver que la copia superficial hace referencia a las listas internas marcando id(a[0]) == id(b[0])dónde b = list(a).

Sukrit Kalra avatar Jul 26 '2013 05:07 Sukrit Kalra

En Python, hay un módulo llamado copycon dos funciones útiles:

import copy
copy.copy()
copy.deepcopy()

copy()es una función de copia superficial. Si el argumento dado es una estructura de datos compuesta, por ejemplo una lista , entonces Python creará otro objeto del mismo tipo (en este caso, una nueva lista ), pero para todo lo que esté dentro de la lista anterior, solo se copia su referencia. Piénselo como:

newList = [elem for elem in oldlist]

Intuitivamente, podríamos suponer que deepcopy()seguiría el mismo paradigma, y ​​la única diferencia es que para cada elemento llamaremos recursivamente deepcopy (al igual que la respuesta de mbguy )

¡pero esto está mal!

deepcopy()en realidad conserva la estructura gráfica de los datos compuestos originales:

a = [1,2]
b = [a,a] # there's only 1 object a
c = deepcopy(b)

# check the result
c[0] is a # False, a new object a_1 is created
c[0] is c[1] # True, c is [a_1, a_1] not [a_1, a_2]

Esta es la parte complicada: durante el proceso de deepcopy(), se utiliza una tabla hash (diccionario en Python) para asignar cada referencia de objeto antiguo a cada referencia de objeto nueva, lo que evita duplicados innecesarios y, por lo tanto, preserva la estructura de los datos compuestos copiados.

Documentos oficiales

watashiSHUN avatar Sep 25 '2015 22:09 watashiSHUN

Si el contenido de la lista son tipos de datos primitivos, puede utilizar una comprensión

new_list = [i for i in old_list]

Puedes anidarlo para listas multidimensionales como:

new_grid = [[i for i in row] for row in grid]
aljgom avatar Apr 16 '2017 13:04 aljgom

@Sukrit Kalra

No.1: list(), [:], copy.copy()son todas copias superficiales. Si un objeto es compuesto, no todos son adecuados. Necesitas usar copy.deepcopy().

No.2: b = adirectamente, ay btienen la misma referencia, cambiar aes igual que cambiar b.

establecer a a b

si lo asigna adirectamente by acomparte buna referencia.

>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = a
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0] = 1
>>> a
[1, [4, 5, 6]]
>>> b
[1, [4, 5, 6]]


>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = a
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0][1] = 10
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b
[[1, 10, 3], [4, 5, 6]]

instantánea

porlist()

list()y [:]son iguales. Excepto los cambios de la primera capa, se transferirán todos los cambios de las demás capas.

>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = list(a)
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0] = 1
>>> a
[1, [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]


>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = list(a)
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0][1] = 10
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b
[[1, 10, 3], [4, 5, 6]]

por[:]

>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = a[:]
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0] = 1
>>> a
[1, [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]


>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = a[:]
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0][1] = 10
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b
[[1, 10, 3], [4, 5, 6]]

list() y [:] cambian las otras capas, excepto la primera capa

# =========== [:] ===========
>>> a = [[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b = a[:]
>>> a
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> a[0][2] = 4
>>> a
[[1, 2, 4], [4, 5, 6]]
>>> b
[[1, 2, 4], [4, 5, 6]]


>>> a = [[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b = a[:]
>>> a
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> a[0][2][0] = 999
>>> a
[[1, 2, [999, 6]], [4, 5, 6]]
>>> b
[[1, 2, [999, 6]], [4, 5, 6]]



# =========== list() ===========
>>> a = [[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b = list(a)
>>> a
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> a[0][2] = 4
>>> a
[[1, 2, 4], [4, 5, 6]]
>>> b
[[1, 2, 4], [4, 5, 6]]


>>> a = [[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b = list(a)
>>> a
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> b
[[1, 2, [3.5, 6]], [4, 5, 6]]
>>> a[0][2][0] = 999
>>> a
[[1, 2, [999, 6]], [4, 5, 6]]
>>> b
[[1, 2, [999, 6]], [4, 5, 6]]

porcopy()

Encontrará que copy()la función es la misma que list()y [:]. Todos ellos son copias superficiales .

Para obtener mucha más información sobre la copia superficial y la copia profunda, tal vez pueda consultar aquí .

>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = copy.copy(a)
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0][1] = 10
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b
[[1, 10, 3], [4, 5, 6]]

pordeepcopy()

>>> import copy
>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = copy.deepcopy(a)
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0] = 1
>>> a
[1, [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]


>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = copy.deepcopy(a)
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0][1] = 10
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]

Mystic avatar Dec 16 '2020 01:12 Mystic

Si los elementos de su lista son objetos inmutables , entonces puede usar esto; de lo contrario, debe usarlo deepcopydesde copyel módulo.

También puedes usar la forma más corta para una copia profunda listcomo esta.

a = [0,1,2,3,4,5,6,7,8,9,10]
b = a[:] #deep copying the list a and assigning it to b
print id(a)
20983280
print id(b)
12967208

a[2] = 20
print a
[0, 1, 20, 3, 4, 5, 6, 7, 8, 9,10]
print b
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10]
tailor_raj avatar Jul 26 '2013 06:07 tailor_raj