¿Por qué Python omite elementos cuando modifico una lista mientras estoy iterando sobre ella?

Actualmente estoy desarrollando un progtwig en Python y acabo de notar que algo andaba mal con el bucle foreach en el lenguaje, o tal vez con la estructura de la lista. Solo daré un ejemplo genérico de mi problema para simplificar, ya que tengo el mismo comportamiento erróneo tanto en mi progtwig como en mi ejemplo genérico:

x = [1,2,2,2,2] for i in x: x.remove(i) print x 

Bueno, el problema aquí es simple, pensé que este código debía eliminar 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 por adelantado.

Edit: no quiero vaciar una lista, esto es solo un ejemplo …

    Este es un comportamiento bien documentado en Python, por el que no se supone que modifique la lista que se está iterando. Intenta esto en su lugar:

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

    El [:] devuelve una “porción” de x , que contiene todos sus elementos, y por lo tanto es una copia de x .

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

    Hazlo al revés. O por favor indique su verdadero problema.

    Creo que, en términos generales, cuando escribes:

     for x in lst: # loop body goes here 

    Bajo el capó, Python 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, ¿quizás entonces podrá ver por qué obtiene el resultado que obtiene?

    Esencialmente, Python utiliza un puntero en movimiento para recorrer la lista. El puntero comienza apuntando al primer elemento. Luego eliminas el primer elemento, lo que convierte al segundo elemento en el nuevo primer elemento. Luego, el puntero se mueve al segundo segundo elemento, anteriormente tercer elemento. Y así. (podría ser más claro si usa [1,2,3,4,5] en lugar de [1,2,2,2,2] como su lista de muestra)

    ¿Por qué no usas simplemente?

     x = [] 

    Probablemente sea porque estás cambiando la misma matriz sobre la que estás iterando.

    Pruebe la respuesta de Chris-Jester Young si desea despejar la matriz a su manera.

    Sé que este es un post antiguo con una respuesta aceptada, pero para aquellos que aún puedan aparecer …

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

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

    Esperemos que lo visual ayude a aclarar.

    Estoy de acuerdo con John Fouhy con respecto a la condición de descanso. El desplazamiento de una copia de la lista funciona para el método remove (), como sugirió Chris Jester-Young. Pero si uno necesita hacer pop () elementos específicos, entonces iterar en trabajos inversos, como mencionó Erik, en cuyo caso la operación se puede realizar 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)