¿Cómo hacer una copia profunda de una lista?

Tengo algún problema con una copia de la lista:

Entonces, después de obtener E0 de 'get_edge' , hago una copia de E0 llamando a 'E0_copy = list(E0)' . Aquí supongo que E0_copy es una copia profunda de E0 , y paso E0_copy a 'karger(E)' . Pero en la función principal.
¿Por qué el resultado de 'print E0[1:10]' antes del bucle for no es el mismo que el del bucle for?

A continuación se muestra mi código:

 def get_graph(): f=open('kargerMinCut.txt') G={} for line in f: ints = [int(x) for x in line.split()] G[ints[0]]=ints[1:len(ints)] return G def get_edge(G): E=[] for i in range(1,201): for v in G[i]: if v>i: E.append([i,v]) print id(E) return E def karger(E): import random count=200 while 1: if count == 2: break edge = random.randint(0,len(E)-1) v0=E[edge][0] v1=E[edge][1] E.pop(edge) if v0 != v1: count -= 1 i=0 while 1: if i == len(E): break if E[i][0] == v1: E[i][0] = v0 if E[i][1] == v1: E[i][1] = v0 if E[i][0] == E[i][1]: E.pop(i) i-=1 i+=1 mincut=len(E) return mincut if __name__=="__main__": import copy G = get_graph() results=[] E0 = get_edge(G) print E0[1:10] ## this result is not equal to print2 for k in range(1,5): E0_copy=list(E0) ## I guess here E0_coypy is a deep copy of E0 results.append(karger(E0_copy)) #print "the result is %d" %min(results) print E0[1:10] ## this is print2 

E0_copy no es una copia profunda. No hace una copia profunda utilizando list() (Ambas list(...) y testList[:] son copias superficiales).

Utiliza copy.deepcopy(...) para copiar en profundidad una lista.

 deepcopy(x, memo=None, _nil=[]) Deep copy operation on arbitrary Python objects. 

Vea el siguiente fragmento de código:

 >>> 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 vea la operación de deepcopy

 >>> 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]] 

Creo que muchos progtwigdores se han topado con uno o dos problemas de entrevista en los que se les pide que copien una lista enlazada, ¡sin embargo, este problema no es tan fácil como parece!

En Python, hay un módulo llamado “copia” con 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 antigua, solo se copia su referencia

 # think of it like newList = [elem for elem in oldlist] 

De manera intuitiva, podríamos asumir que deepcopy () seguiría el mismo paradigma, y ​​la única diferencia es que para cada elemento llamamos de forma recursiva deepcopy (como la respuesta de mbcoder)

¡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 # return False, a new object a' is created c[0] is c[1] # return True, c is [a',a'] not [a',a''] 

esta es la parte difícil, durante el proceso de copia profunda () se utiliza una tabla hash (diccionario en python) para mapear: “old_object ref on new_object ref”, esto evita duplicados innecesarios y así preserva la estructura de los datos compuestos copiados

doc oficial

Si los contenidos de la lista son tipos de datos primitivos, puede utilizar una comprensión

 new_list = [i for i in old_list] 

Puedes anidarla para listas multidimensionales como:

 new_grid = [[i for i in row] for row in grid] 

Si los list elements su list elements son immutable objects entonces puede usar esto, de lo contrario tendrá que usar deepcopy desde el módulo de copy .

También puedes usar la forma más corta para copiar en profundidad una list como 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] 

Sólo una función de copia profunda recursiva.

 def deepcopy(A): rt = [] for elem in A: if isinstance(elem,list): rt.append(deepcopy(elem)) else: rt.append(elem) return rt 

Edición: Como mencionó Cfreak, esto ya está implementado en el módulo de copy .

Con respecto a la lista como un árbol, la copia_cita en python se puede escribir de forma más compacta como

 def deep_copy(x): if not isinstance(x, list): return x else: return map(deep_copy, x) 

Esto es mas pythonico

 my_list = [0, 1, 2, 3, 4, 5] # some list my_list_copy = list(my_list) # my_list_copy and my_list does not share reference now. 

NOTA: Esto no es seguro con una lista de tipos mutables