2012-01-05 11 views
90

Tomemos un ejemplolista de Python por valor no por referencia

a=['help', 'copyright', 'credits', 'license'] 
b=a 
b.append('XYZ') 
b 
['help', 'copyright', 'credits', 'license', 'XYZ'] 
a 
['help', 'copyright', 'credits', 'license', 'XYZ'] 

yo quería añadir valor en la lista 'B', pero el valor de la lista 'A' también han cambiado.
creo que tengo poca idea de por qué es como esto (pitón pasa listas de referencia).
Mi pregunta es "¿cómo puedo pasar por valor, de modo que añadiendo 'B' valores de cambio does't en 'a'?"

Respuesta

137

como respondida en el official Python FAQ:

b = a[:] 
+3

No funciona para mí. Cualquier cambio que haga a 'b' también se ve en' a'. – Mannix

+1

@Mannix ¿Puede publicar el [código completo] (https://stackoverflow.com/help/mcve) que tiene que muestra el problema (es decir, una afirmación debe fallar) en una nueva pregunta? Lo más probable es que no estés modificando la lista en sí, sino sus elementos. Cree una [copia en profundidad] (https://docs.python.org/dev/library/copy.html#copy.deepcopy) si desea una nueva lista cuyos elementos también sean copias. – phihag

5

Para crear una copia de una lista hacer esto:

b = a[:] 
13

Además, se puede hacer:

b = list(a) 

Esto funcionará para cualquier secuencia, incluso aquellas que no admiten indexadores y sectores ...

5

Al hacer b = a sólo tiene que crear otro puntero a la misma memoria de un , Por eso, cuando usted adiciona b, un cambios también.

Es necesario crear copia deun y que se han hecho de esta manera:

b = a[:] 
106

Para copiar una lista que puede utilizar o list(a)a[:]. En ambos casos, se crea un nuevo objeto.
Estos dos métodos, sin embargo, tienen limitaciones con colecciones de objetos mutables como objetos internos mantienen sus referencias intacta:

>>> a = [[1,2],[3],[4]] 

>>> b = a[:] 
>>> c = list(a) 

>>> c[0].append(9) 

>>> a 
[[1, 2, 9], [3], [4]] 
>>> c 
[[1, 2, 9], [3], [4]] 
>>> b 
[[1, 2, 9], [3], [4]] 
>>> 

Si desea una copia completa de los objetos que necesita copy.deepcopy

>>> from copy import deepcopy 
>>> a = [[1,2],[3],[4]] 

>>> b = a[:] 
>>> c = deepcopy(a) 

>>> c[0].append(9) 

>>> a 
[[1, 2], [3], [4]] 
>>> b 
[[1, 2], [3], [4]] 
>>> c 
[[1, 2, 9], [3], [4]] 
>>> 
+0

¿cuál es la diferencia entre una copia normal y una copia profunda? ¿Por qué ocurre lo que sucede arriba? Creo que tengo un entendimiento general, parece ser como el mismo problema encontrado por la operación en la segunda capa. ¿Cómo funciona internamente? – AsheKetchum

2

I se encontró que podemos usar extender() para implementar la función de copiar()

a=['help', 'copyright', 'credits', 'license'] 
b = [] 
b.extend(a) 
b.append("XYZ") 
18

En términos de rendimiento, mi respuesta favorita sería:

b.extend(a) 

comprobar cómo las alternativas relacionadas se comparan entre sí en términos de rendimiento:

In [1]: import timeit 

In [2]: timeit.timeit('b.extend(a)', setup='b=[];a=range(0,10)', number=100000000) 
Out[2]: 9.623248100280762 

In [3]: timeit.timeit('b = a[:]', setup='b=[];a=range(0,10)', number=100000000) 
Out[3]: 10.84756088256836 

In [4]: timeit.timeit('b = list(a)', setup='b=[];a=range(0,10)', number=100000000) 
Out[4]: 21.46313500404358 

In [5]: timeit.timeit('b = [elem for elem in a]', setup='b=[];a=range(0,10)', number=100000000) 
Out[5]: 66.99795293807983 

In [6]: timeit.timeit('for elem in a: b.append(elem)', setup='b=[];a=range(0,10)', number=100000000) 
Out[6]: 67.9775960445404 

In [7]: timeit.timeit('b = deepcopy(a)', setup='from copy import deepcopy; b=[];a=range(0,10)', number=100000000) 
Out[7]: 1216.1108016967773 
+1

Gracias por llevar el rendimiento a la discusión, esto me ayudó a tomar una decisión sobre qué método usar. – Monkpit

+1

Acabo de encontrar su respuesta, gracias por esta respuesta de alta calidad. Cuando se habla de Python, a menudo el rendimiento no se considera y para grandes conjuntos de datos hace la diferencia. – Artur

+0

Me gusta esta respuesta, sin embargo, no se relaciona con los valores de la lista. Como mencionó Jordan Pagni, si su lista es multidimensional, como en listas dentro de listas (y más), entonces la única solución que funcionará es la que demora más tiempo: b = copia profunda (a) –

5

Si desea copiar una lista unidimensional, utilice

b = a[:] 

Sin embargo, si a es una lista bidimensional, esto no va a funcionar para usted. Es decir, cualquier cambio en a también se reflejará en b. En ese caso, utilice

b = [[a[x][y] for y in range(len(a[0]))] for x in range(len(a))] 
3

Como se ha mencionado por phihag en su respuesta,

b = a[:] 

de trabajo para su caso desde rebanar una lista crea un nuevo identificador de memoria de la lista (lo que significa que ya no están hacer referencia al mismo objeto en su memoria y los cambios que realice en uno no se reflejarán en el otro.)

Sin embargo, existe un pequeño problema. Si su lista es multidimensional, como en listas dentro de listas, simplemente rebanar no resolverá este problema. Los cambios realizados en las dimensiones superiores, es decir, las listas dentro de la lista original, se compartirán entre los dos.

No se preocupe, hay una solución. La copia del módulo tiene una ingeniosa técnica de copia que soluciona este problema.

from copy import deepcopy 

b = deepcopy(a) 

copiará una lista con una nueva identificación de memoria sin importar cuántos niveles de listas contenga!

+0

¡Gran respuesta, Jordan! ¡Gracias! ¿Conoces la razón de esto? – Felipe

1

recomendaría la siguiente solución:

b = [] 
b[:] = a 

Esto copiará todos los elementos de A a B. La copia será una copia de valor, no una copia de referencia.

Cuestiones relacionadas