over loop index for examples comprehension python list for-loop iteration

loop - list comprehension python



¿Cuál es el significado de la lista (4)

(Además de la respuesta @Coldspeed)

Mira los siguientes ejemplos:

words = [''cat'', ''window'', ''defenestrate''] words2 = words words2 is words

resultados: True

Significa que los nombres word y words2 refieren al mismo objeto.

words = [''cat'', ''window'', ''defenestrate''] words2 = words[:] words2 is words

resultados: False

En este caso, hemos creado el nuevo objeto.

Esta pregunta ya tiene una respuesta aquí:

Este código es de la documentación de Python. Estoy un poco confundido.

words = [''cat'', ''window'', ''defenestrate''] for w in words[:]: if len(w) > 6: words.insert(0, w) print(words)

Y lo siguiente es lo que pensé al principio:

words = [''cat'', ''window'', ''defenestrate''] for w in words: if len(w) > 6: words.insert(0, w) print(words)

¿Por qué este código crea un bucle infinito y el primero no?


Echemos un vistazo a iterador e iterables:

Un iterable es un objeto que tiene un método __iter__ que devuelve un iterador, o que define un método __getitem__ que puede tomar índices secuenciales a partir de cero (y genera un IndexError cuando los índices ya no son válidos). Entonces, un iterable es un objeto del que puede obtener un iterador.

Un iterador es un objeto con un método next (Python 2) o __next__ (Python 3).

iter(iterable) devuelve un objeto iterador, y list_obj[:] devuelve un nuevo objeto de lista, copia exacta de list_object.

En tu primer caso:

for w in words[:]

El bucle for iterará sobre una nueva copia de la lista, no las palabras originales. Cualquier cambio en las palabras no tiene efecto en la iteración del ciclo, y el ciclo termina normalmente.

Así es como funciona el bucle:

  1. loop llama al método iter en iterable e itera sobre el iterador

  2. loop llama al next método en el objeto iterador para obtener el siguiente elemento del iterador. Este paso se repite hasta que no queden más elementos.

  3. el ciclo termina cuando se StopIteration una excepción StopIteration .

En tu segundo caso:

words = [''cat'', ''window'', ''defenestrate''] for w in words: if len(w) > 6: words.insert(0, w) print(words)

Está iterando sobre las palabras de la lista original y agregando elementos a las palabras tiene un impacto directo en el objeto iterador. Por lo tanto, cada vez que se actualizan sus palabras, el objeto iterador correspondiente también se actualiza y, por lo tanto, crea un bucle infinito.

Mira esto:

>>> l = [2, 4, 6, 8] >>> i = iter(l) # returns list_iterator object which has next method >>> next(i) 2 >>> next(i) 4 >>> l.insert(2, ''A'') >>> next(i) ''A''

Cada vez que actualice su lista original antes de StopIteration , obtendrá el iterador actualizado y el next regresará en consecuencia. Es por eso que tu ciclo se ejecuta infinitamente.

Para obtener más información sobre la iteración y el protocolo de iteración, puede consultar here .


Esta es una de las trampas! de pitón, que puede escapar de los principiantes.

Las words[:] es la salsa mágica aquí.

Observar:

>>> words = [''cat'', ''window'', ''defenestrate''] >>> words2 = words[:] >>> words2.insert(0, ''hello'') >>> words2 [''hello'', ''cat'', ''window'', ''defenestrate''] >>> words [''cat'', ''window'', ''defenestrate'']

Y ahora sin el [:] :

>>> words = [''cat'', ''window'', ''defenestrate''] >>> words2 = words >>> words2.insert(0, ''hello'') >>> words2 [''hello'', ''cat'', ''window'', ''defenestrate''] >>> words [''hello'', ''cat'', ''window'', ''defenestrate'']

Lo principal a tener en cuenta aquí es que las words[:] devuelven una copy de la lista existente, por lo que está iterando sobre una copia, que no se modifica.

Puede verificar si se está refiriendo a las mismas listas usando id() :

En el primer caso:

>>> words2 = words[:] >>> id(words2) 4360026736 >>> id(words) 4360188992 >>> words2 is words False

En el segundo caso:

>>> id(words2) 4360188992 >>> id(words) 4360188992 >>> words2 is words True

Vale la pena señalar que [i:j] se llama operador de corte , y lo que hace es devolver una copia nueva de la lista comenzando desde el índice i , hasta el índice j (pero sin incluirlo).

Entonces, las words[0:2] te dan

>>> words[0:2] [''hello'', ''cat'']

Omitir el índice inicial significa que el valor predeterminado es 0 , mientras que omitir el último índice significa que el valor predeterminado es len(words) , y el resultado final es que recibe una copia de la lista completa .

Si desea que su código sea un poco más legible, le recomiendo el módulo de copy .

from copy import copy words = [''cat'', ''window'', ''defenestrate''] for w in copy(words): if len(w) > 6: words.insert(0, w) print(words)

Básicamente, hace lo mismo que su primer fragmento de código, y es mucho más legible.

Alternativamente (como lo menciona DSM en los comentarios) y en python> = 3, también puede usar words.copy() que hace lo mismo.


words[:] copia todos los elementos en words en una nueva lista. Entonces, cuando iteras sobre las words[:] , en realidad estás iterando sobre todos los elementos que las words actualmente. Entonces, cuando modifica words , los efectos de esas modificaciones no son visibles en las words[:] (porque invocó words[:] antes de comenzar a modificar las words )

En el último ejemplo, está iterando sobre words , lo que significa que cualquier cambio que realice en las words es visible para su iterador. Como resultado, cuando inserta en el índice 0 de words , "sube" todos los demás elementos en words por un índice. Entonces, cuando pase a la siguiente iteración de su ciclo for, obtendrá el elemento en el siguiente índice de words , pero ese es solo el elemento que acaba de ver (porque insertó un elemento al comienzo de la lista, mover todo el otro elemento hacia arriba por un índice).

Para ver esto en acción, intente el siguiente código:

words = [''cat'', ''window'', ''defenestrate''] for w in words: print("The list is:", words) print("I am looking at this word:", w) if len(w) > 6: print("inserting", w) words.insert(0, w) print("the list now looks like this:", words) print(words)