Jak wykonać pętlę przez generator

81

Jak jedna pętla może przejść przez generator? Myślałem o tym w ten sposób:

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

Czy jest bardziej pytoniczny sposób?

iTayb
źródło
Sugerowałbym użycie break; niecontinue
Jon Clements
Właściwie zrobiłbym to w ten sposób w przypadku, gdy generator może rzucić wyjątek na element, ale nie chcesz przerywać iteracji.
robbrit

Odpowiedzi:

145

Po prostu

for x in gen:
    # whatever

da rade. Zauważ, że if genzawsze zwraca True.

Sven Marnach
źródło
6
Nie, if gennie zawsze wraca True. Jeśli PO za function_that_returns_a_generator()zwrotów None, genocenia się Falsew ifoświadczeniu.
drevicko
44
@drevicko: Zakładałem, że function_that_returns_a_generator()zwraca generator (odważne założenie, prawda?). Nonenie jest generatorem.
Sven Marnach
Ponieważ OP prosi o „pythonic sposób”, to odpowiedź wydaje się całkiem prawda, zważywszy, że Python opowiada EAFP ;-)
DerMike
17
for item in function_that_returns_a_generator(param1, param2):
    print item

Nie musisz martwić się testem, aby sprawdzić, czy funkcja zwraca coś, tak jakby nic nie zostało zwrócone, nie wejdziesz do pętli.

Christian Witts
źródło
9

W przypadku, gdy nie potrzebujesz wyjścia generatora, ponieważ zależy Ci tylko na jego skutkach ubocznych, możesz użyć następującego jednoliniowca:

for _ in gen: pass
mmj
źródło
3
lub po prostulist(gen)
1919
7

Możesz po prostu zapętlić to:

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

Pamiętaj jednak, że pętlę można wykonać tylko raz. Następnym razem generator będzie pusty:

>>> for i in gen: print i
>>> 
Wojciech Kałuski
źródło
4

Po prostu potraktuj to jak każdą inną iterowalną:

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

Zauważ, że if gen:zawsze będzie True, więc jest to fałszywy test

Jon Clements
źródło
2

Jeśli chcesz ręcznie poruszać się po generatorze (tj. Ręcznie pracować z każdą pętlą), możesz zrobić coś takiego:

    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
źródło
1
from pdb import set_trace # no () :)
Vlad K.
1

Pozostałe odpowiedzi są dobre w przypadku skomplikowanych scenariuszy. Jeśli chcesz po prostu przesłać elementy do listy:

x = list(generator)

(lub, jeśli chcesz po prostu uruchomić generator, aby coś zrobił, po prostu list(generator).

Do prostego przetwarzania wstępnego użyj wyrażeń listowych:

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

Lub gdy chcesz wykonać proste funkcje:

# didn't assign to variable b/c we don't care about what the print() function returns
[print(x) for x in gen]
crypdick
źródło