2009-04-12 11 views
8

Actualmente estoy desarrollando un programa en python y me acabo de dar cuenta de que algo andaba mal con el bucle foreach en el lenguaje, o tal vez la estructura de la lista. Voy a dar un ejemplo genérico de mi problema de simplificar, desde que sale el mismo comportamiento erróneo tanto en mi programa y mi genérica ejemplo:Comportamiento extraño de Python en for loop o listas

x = [1,2,2,2,2] 

for i in x: 
    x.remove(i) 

print x   

Bueno, el problema aquí es simple, que a pesar de que este código se suponía que eliminaría todos los elementos de una lista. Bueno, el problema es que después de su ejecución, siempre obtengo 2 elementos restantes en la lista.

¿Qué estoy haciendo mal? Gracias por toda la ayuda de antemano.

Editar: No quiero vaciar una lista, esto es sólo un ejemplo ...

+0

El problema que experimenta tiene soluciones a continuación, pero no puedo evitar pensar que se debe acortar a "x = []". ¿Podría ser más interesante si publica el código real que le causa problemas? – gnud

+0

Deberías publicar tu problema real. list.remove es bastante ineficiente, porque tiene que buscar en la lista, y luego desplazar hacia delante todos los elementos que siguen a la eliminación. – Miles

Respuesta

30

Este es un comportamiento bien documentada en Python, que no se supone modificar la lista sea iterada mediante. Tal vez puedas probar:

for i in x[:]: 
    x.remove(i) 

Los [:] devuelve una "rebanada" de x, que pasa a contener todos sus elementos, y por tanto es efectivamente una copia de x.

+0

Vea también: http://docs.python.org/tutorial/controlflow.html#for-statements –

+0

Gracias, eso fue :) – rogeriopvl

+0

Esto no explica por qué en la pregunta de rogeriopvl la lista contiene dos elementos. Si esta explicación fuera cierta, la lista debería haber estado intacta –

11

Cuando elimina un elemento, y el for-loop incs al siguiente índice, omite un elemento.

Hágalo hacia atrás. O por favor, indique su problema real.

3

¿Por qué no sólo tiene que utilizar:

x = [] 

Es probablemente porque se está cambiando la misma matriz que está interactuando sobre.

Pruebe la respuesta de Chris-Jester Young si desea borrar la matriz en su dirección.

4

creo que, a grandes rasgos, que cuando se escribe:

for x in lst: 
    # loop body goes here 

bajo el capó, pitón está haciendo algo como esto:

i = 0 
while i < len(lst): 
    x = lst[i] 
    # loop body goes here 
    i += 1 

Si inserta lst.remove(x) para el cuerpo del bucle, tal vez entonces podrás ver por qué obtienes el resultado que obtienes?

Básicamente, python usa un puntero en movimiento para recorrer la lista. El puntero comienza apuntando al primer elemento. A continuación, elimina el primer elemento, por lo que el elemento segundo es el primer elemento nuevo. Luego, el puntero se mueve al nuevo segundo, previamente al tercer elemento. Y así. (podría ser más claro si utiliza [1,2,3,4,5] en lugar de [1,2,2,2,2] como su lista de muestras)

1

Estoy de acuerdo con John Fouhy con respecto a la condición de ruptura . Atravesar una copia de la lista funciona para el método remove(), como sugirió Chris Jester-Young. Pero si uno necesita pop() elementos específicos, entonces iterar en reversa funciona, como mencionó Erik, en cuyo caso la operación se puede hacer en su lugar.Por ejemplo:

def r_enumerate(iterable): 
    """enumerator for reverse iteration of an iterable""" 
    enum = enumerate(reversed(iterable)) 
    last = len(iterable)-1 
    return ((last - i, x) for i,x in enum) 

x = [1,2,3,4,5] 
y = [] 
for i,v in r_enumerate(x): 
    if v != 3: 
     y.append(x.pop(i)) 
    print 'i=%d, v=%d, x=%s, y=%s' %(i,v,x,y) 


o con xrange:

x = [1,2,3,4,5] 
y = [] 
for i in xrange(len(x)-1,-1,-1): 
    if x[i] != 3: 
     y.append(x.pop(i)) 
    print 'i=%d, x=%s, y=%s' %(i,x,y) 
1

Sé que esto es un antiguo puesto con una respuesta aceptada, pero para aquellos que todavía puede venir ...

Algunas respuestas anteriores han indicado que es una mala idea cambiar un iterable durante la iteración. Sino como una forma de resaltar lo que está sucediendo ...

>>> x=[1,2,3,4,5] 
>>> for i in x: 
...  print i, x.index(i) 
...  x.remove(i) 
...  print x 
... 
1 0 
[2, 3, 4, 5] 
3 1 
[2, 4, 5] 
5 2 
[2, 4] 

Con suerte lo visual ayuda a aclarar.