2011-01-03 14 views
5

Pensé que conocía a Python hasta esta noche. ¿Cuál es la forma correcta de hacer algo como esto? Aquí está mi código:Confusión de objetos Python: a = b, modifica b y a cambia!

a = ["one", "two", "three"] 
b = a # here I want a complete copy that when b is changed, has absolutely no effect on a 
b.append["four"] 
print a # a now has "four" in it 

Básicamente quiero saber, en lugar del paso b = a, ¿cómo podría correctamente hacer una copia de una lista o diccionario para que cuando b se cambia a no cambia junto con él?

+5

Bueno, no conoces Python. O al menos no sabes una parte importante de ella, qué variables son. Ver una pregunta similar en SO o, p. Ej. http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables. – delnan

+5

@delnan para ser justos, no es un escollo común para las personas que son nuevas en Python entender que la asignación de variables que involucra listas asigna referencias, aunque el reclamo "Pensé que sabía Python" tiende a indicar que no son "nuevas":) –

Respuesta

11

Lo que está experimentando es el concepto de referencias. Todos los objetos en Python tienen una referencia y cuando asigna uno o dos nombres a y b, esto da como resultado a y b apuntando al mismo objeto .

>>> a = range(3) 
>>> b = a      # same object 
>>> b.append(3) 
>>> a, b      # same contents 
([0, 1, 2, 3], [0, 1, 2, 3]) 

Con las listas, puede hacer que crear una nueva lista b que es una copia de otro a usando b = a[:].

>>> a = range(3) 
>>> b = a[:]     # make b a new copy of a 
>>> b.append(3) 
>>> a, b      # a is left unchanged 
([0, 1, 2], [0, 1, 2, 3]) 

Para una solución más general para cualquier objeto, utilice el copy module. Una copia superficial copiará las referencias almacenadas dentro del objeto que está copiando, mientras que una copia profunda hará de forma recursiva copias nuevas de todos los objetos.

>>> a = [range(2), range(3)] 
>>> b = copy.copy(a)   # shallow copy of a, equivalent to a[:] 
>>> b[0] = range(4) 
>>> a, b      # setting an element of b leaves a unchanged 
([[0, 1], [0, 1, 2]], [[0, 1, 2, 3], [0, 1, 2]]) 
>>> b[1].append(3) 
>>> a, b      # modifying an element of b modifies the element in a 
([[0, 1], [0, 1, 2, 3]], [[0, 1, 2, 3], [0, 1, 2, 3]]) 

>>> a = [range(2), range(3)] 
>>> b = copy.deepcopy(a)  # deep recursive copy of a 
>>> b[1].append(3) 
>>> a, b      # modifying anything in b leaves a unchanged 
([[0, 1], [0, 1, 2]], [[0, 1], [0, 1, 2, 3]]) 
+0

¿Qué es una copia profunda y cuál es una copia superficial. noté que la cadena dict.copy .__ doc__ dice que es una copia "superficial". ¿cual es la diferencia? – james

+5

Revisa http: // stackoverflow.com/questions/184710/what-is-the-difference-between-a-deep-copy-and-a-shallow-copy – Sapph

+0

Esa es en realidad una copia superficial, pero por lo demás es la forma correcta de copiar una lista. – Keith

1

La forma correcta de copiar un objeto es

from copy import copy 
a = [1, 2, 3] 
b = copy(a) 

bastante simple. No hay atajos para las listas:

a = [1, 2, 3] 
b = a[:] 

También hay deepcopy() si desea copiar los objetos en la lista también.

+0

Tenga cuidado con el uso excesivo de deepcopy. Esto puede hacer explotar el uso de su memoria y, a veces, genera errores extraños de "objeto no desmontable". Para casi todos los casos de uso, no * necesita * una copia, y para los demás casos, una copia poco clara servirá. – bukzor

1

Aquí hay 3 formas de hacer una copia de la lista a:

Uso notación de corte:

copy_of_a = a[:] 

utilizar la lista constructor:

copy_of_a = list(a) 

utilizar el módulo de copia:

from copy import copy 
copy_of_a = copy(a) 

Todas estas son copias superficiales, que son suficientes para su pregunta. Para conocer la diferencia entre la copia superficial y la copia profunda, lea documentation of the copy module.

Cuestiones relacionadas