Comportamiento del iterador de la lista de Python y siguiente (iterador)


147

Considerar:

>>> lst = iter([1,2,3])
>>> next(lst)
1
>>> next(lst)
2

Entonces, avanzar el iterador es, como se esperaba, manejado mutando ese mismo objeto.

Siendo este el caso, esperaría:

a = iter(list(range(10)))
for i in a:
   print(i)
   next(a)

para omitir cada segundo elemento: la llamada a nextdebe avanzar el iterador una vez, luego la llamada implícita realizada por el bucle debe avanzar por segunda vez, y se le asignará el resultado de esta segunda llamada i.

No lo hace. El bucle imprime todos los elementos de la lista, sin omitir ninguno.

Mi primer pensamiento fue que esto podría suceder porque el bucle invoca iterlo que se pasa, y esto podría dar un iterador independiente; este no es el caso, como lo hemos hecho iter(a) is a.

Entonces, ¿por qué nextno parece avanzar el iterador en este caso?

Respuestas:


197

Lo que ve es que el intérprete repite el valor de retorno, next()además de iimprimir cada iteración:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    next(a)
... 
0
1
2
3
4
5
6
7
8
9

También lo 0es la salida de print(i), 1el valor de retorno next(), el eco del intérprete interactivo, etc. Hay solo 5 iteraciones, cada iteración resulta en 2 líneas que se escriben en el terminal.

Si asigna la salida de las next()cosas funcionan como se esperaba:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    _ = next(a)
... 
0
2
4
6
8

o imprima información adicional para diferenciar la print()salida del eco del intérprete interactivo:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print('Printing: {}'.format(i))
...    next(a)
... 
Printing: 0
1
Printing: 2
3
Printing: 4
5
Printing: 6
7
Printing: 8
9

En otras palabras, next()funciona como se esperaba, pero debido a que devuelve el siguiente valor del iterador, repetido por el intérprete interactivo, se le hace creer que el bucle tiene su propia copia del iterador de alguna manera.


13
No estaba al tanto de este comportamiento por parte del intérprete. Me alegro de haberlo descubierto antes de perder mucho tiempo preguntándome mientras resolvía algún problema real.
brandizzi

55
... * muere *. Lo peor de todo es que puedo recordar haber mencionado exactamente este comportamiento de intérprete a alguien tal vez hace una semana.
lvc

interesante. Intenté para i en a: next (a); imprime i y pensé que saltaría a 1 e imprimir 1,3,5,7,9. Pero aún así es 0,2,4,6,8. ¿Por qué?
user2290820

3
iya fue asignado. next(a)significa que 2se asigna la siguiente iteración i, luego se mueve de anuevo, imprime i, etc.
Martijn Pieters

1
Esto no funciona si n es impar: se StopIterationgenera un excedente cuando next(a)se llama después de que se agote la lista.
Raf

13

Lo que sucede es que next(a)devuelve el siguiente valor de a, que se imprime en la consola porque no se ve afectado.

Lo que puede hacer es afectar una variable con este valor:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    b=next(a)
...
0
2
4
6
8

8

Las respuestas existentes me parecen un poco confusas, ya que solo indican indirectamente lo esencial desconcertante en el ejemplo del código: tanto * la "impresión i" como la "siguiente (a)" están causando que se impriman sus resultados.

Como están imprimiendo elementos alternos de la secuencia original, y es inesperado que se imprima la declaración "next (a)", parece que la declaración "print i" está imprimiendo todos los valores.

A la luz de esto, se hace más claro que asignar el resultado de "siguiente (a)" a una variable inhibe la impresión de su resultado, de modo que solo se imprimen los valores alternativos de la variable de bucle "i". Del mismo modo, hacer que la declaración "print" emita algo más distintivo también lo desambigua.

(Una de las respuestas existentes refuta las otras porque esa respuesta es tener el código de ejemplo evaluado como un bloque, por lo que el intérprete no informa los valores intermedios para "next (a)".)

Lo atractivo en responder preguntas, en general, es ser explícito sobre lo que es obvio una vez que se sabe la respuesta. Puede ser esquivo. Del mismo modo, criticar las respuestas una vez que las comprenda. Es interesante...


2

Algo está mal con su Python / Computadora.

a = iter(list(range(10)))
for i in a:
   print(i)
   next(a)

>>> 
0
2
4
6
8

Funciona como se esperaba.

Probado en Python 2.7 y en Python 3+. Funciona correctamente en ambos


55
Obtengo el mismo resultado que @lvc (solo en IDLE, sin embargo, cuando se ejecuta como script obtengo esto))
jamylak

3
@Inbar Rose Solo si se ejecuta como secuencia de comandos.
Quintec

1
Es el comportamiento de poner código a través de un shell interactivo. Si la función devuelve el valor sin ser utilizado, el intérprete lo imprimirá en el shell como salida de depuración
Reishin

2

Para aquellos que aún no entienden.

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    next(a)
... 
0 # print(i) printed this
1 # next(a) printed this
2 # print(i) printed this
3 # next(a) printed this
4 # print(i) printed this
5 # next(a) printed this
6 # print(i) printed this
7 # next(a) printed this
8 # print(i) printed this
9 # next(a) printed this

Como ya han dicho otros, nextaumenta el iterador en 1 como se esperaba. Asignar su valor devuelto a una variable no cambia mágicamente su comportamiento.


1

Se comporta de la manera deseada si se llama como una función:

>>> def test():
...     a = iter(list(range(10)))
...     for i in a:
...         print(i)
...         next(a)
... 
>>> test()
0
2
4
6
8
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.