2010-02-16 18 views
9

Me puede estar faltando algo sobre el comportamiento previsto de la extensión de la lista, pero ¿por qué sucede lo siguiente?Extendiendo una lista de listas en Python?

x = [[],[]] 
y = [[]] * 2 

print x  # [[],[]] 
print y  # [[],[]] 
print x == y # True 

x[0].extend([1]) 
y[0].extend([1]) 

print x # [[1],[]], which is what I'd expect 
print y # [[1],[1]], wtf? 

yo supongo que el operador * está haciendo algo inesperado aquí, aunque no estoy muy seguro de qué. Parece que algo está sucediendo debajo del capó que hace que el x original y el y (antes de llamar a extender) no sean realmente iguales aunque el operador == y el repr parezcan idénticos.

Solo me encontré con esto porque quería rellenar previamente una lista de listas vacías de un tamaño determinado en tiempo de ejecución, y luego me di cuenta de que no estaba funcionando de la manera que imaginaba. Puedo encontrar una mejor manera de hacer lo mismo, pero ahora tengo curiosidad de por qué esto no funcionó. Esto es Python 2.5.2 BTW - No tengo una versión más nueva instalada, así que si esto es un error, no estoy seguro de si ya está solucionado.

+0

Estoy al tanto de lo que hace append, solo estaba inventando un ejemplo artificial por el bien de la pregunta. –

Respuesta

16

En el caso de [something] * 2, python simplemente está haciendo una copia de referencia. Por lo tanto, si el (los) tipo (s) adjunto (s) son mutables, el cambio se reflejará en cualquier lugar al que se haga referencia.

En su ejemplo, y[0] y y[1] apuntan al mismo objeto de lista cerrada. Puede verificar esto haciendo y[0] is y[1] o alternativamente id(y[0]) == id(y[1]).

Sin embargo, puede volver a asignar elementos de la lista, por lo que si se hubiera hecho:

y[0] = [1] 

Se podría haber re-ligado el primer elemento a una nueva lista que contiene el elemento "1", y que sería tienes tu resultado esperado

Los contenedores en python almacenan referencias, y es posible en la mayoría de los contenedores de secuencia hacer referencia al mismo artículo varias veces. Una lista puede referirse a sí misma como un elemento, aunque la utilidad de esto es limitada.

Este problema no se habría llegado si se hubiera multiplicado una lista que contiene los tipos inmutables:

a = [0, 1] * 2 

Lo anterior se le dará la lista [0, 1, 0, 1] y de hecho las dos instancias de 1 apuntan al mismo objeto, pero ya que son inmutables, no puede cambiar el valor del objeto int que contiene "1", solo reasignar elementos.

Al hacerlo: a[1] = 5 daría como resultado a mostrando como [0, 5, 0, 1].

+0

Gracias, eso tiene sentido. –

4

La declaración y = [[]] * 2 enlaza y a una lista que contiene 2 copias de la misma lista. Uso:

y = [[], []] 

o

y = [[] for n in range(2)] 
+4

Técnicamente, son dos referencias a la misma lista, no copias. – Crast

+0

significa, "2 referencias" en lugar de "2 copias", ¿verdad?Sugerí que como edición – kmonsoor

1

y contiene dos referencias a una sola, mutable, lista.

Cuestiones relacionadas