Cómo recorrer un generador

81

¿Cómo se puede recorrer un generador? Pensé de esta manera:

gen = function_that_returns_a_generator(param1, param2)
if gen: # in case the generator is null
    while True:
        try:
            print gen.next()
        except StopIteration:
            break

¿Existe una forma más pitónica?

iTayb
fuente
Sugeriría usar break; nocontinue
Jon Clements
De hecho, lo haría de esta manera en el caso de que el generador pueda lanzar una excepción en un elemento, pero no desea detener la iteración.
robbrit

Respuestas:

145

Simplemente

for x in gen:
    # whatever

hará el truco. Tenga en cuenta que if gensiempre vuelve True.

Sven Marnach
fuente
6
No, if genno siempre regresa True. Si la operación function_that_returns_a_generator()regresa None, se genevalúa Falseen la ifdeclaración.
drevicko
44
@drevicko: estaba asumiendo que function_that_returns_a_generator()devuelve un generador (suposición en negrita, ¿no es así?). Noneno es un generador.
Sven Marnach
Dado que OP solicita una "forma pitónica", esta respuesta parece bastante legítima, dado que Python aboga por EAFP ;-)
DerMike
17
for item in function_that_returns_a_generator(param1, param2):
    print item

No necesita preocuparse por la prueba para ver si su función devuelve algo, ya que si no hay nada devuelto, no ingresará al ciclo.

Christian Witts
fuente
9

En caso de que no necesite la salida del generador porque solo le importan sus efectos secundarios, puede usar el siguiente resumen:

for _ in gen: pass
mmj
fuente
3
o simplementelist(gen)
aiven
7

Simplemente puede recorrerlo:

>>> gen = (i for i in range(1, 4))
>>> for i in gen: print i
1
2
3

Pero tenga en cuenta que solo puede realizar un bucle una vez. La próxima vez que el generador esté vacío:

>>> for i in gen: print i
>>> 
Wojciech Kałuski
fuente
4

Simplemente trátelo como cualquier otro iterable:

for val in function_that_returns_a_generator(p1, p2):
    print val

Tenga en cuenta que if gen:siempre será Verdadero, por lo que es una prueba falsa

Jon Clements
fuente
2

Si desea moverse manualmente a través del generador (es decir, trabajar con cada bucle manualmente), puede hacer algo como esto:

    from pdb import set_trace

    for x in gen:
        set_trace()
        #do whatever you want with x at the command prompt
        #use pdb commands to step through each loop of the generator e.g., >>c #continue   
rysqui
fuente
1
desde pdb import set_trace # no () :)
Vlad K.
1

Las otras respuestas son buenas para escenarios complicados. Si simplemente desea transmitir los elementos a una lista:

x = list(generator)

(o, si solo desea activar el generador para hacer cosas, simplemente list(generator).

Para un preprocesamiento simple, use listas por comprensión:

x = [tup[0] for tup in generator]

O cuando desee ejecutar funciones simples:

# didn't assign to variable b/c we don't care about what the print() function returns
[print(x) for x in gen]
Crypdick
fuente