如何循环通过发电机

怎样才能通过一个发电机循环? 我想过这样的方式:

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

还有比这更简单的方法吗?

133923 次浏览
for item in function_that_returns_a_generator(param1, param2):
print item

You don't need to worry about the test to see if there is anything being returned by your function as if there's nothing returned you won't enter the loop.

Simply

for x in gen:
# whatever

will do the trick. Note that if gen always returns True.

Just treat it like any other iterable:

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

Note that if gen: will always be True, so it's a false test

If you want to manually move through the generator (i.e., to work with each loop manually) then you could do something like this:

    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

In case you don't need the output of the generator because you care only about its side effects, you can use the following one-liner:

for _ in gen: pass

Follow up

Following the comment by aiven I made some performance tests, and while it seems that list(gen) is slightly faster than for _ in gen: pass, it comes out that tuple(gen) is even faster. However, as Erik Aronesty correctly points out, tuple(gen) and list(gen) store the results, so my final advice is to use

tuple(gen)

but only if the generator is not going to loop billions of times soaking up too much memory.

You can simply loop through it:

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

But be aware, that you can only loop one time. Next time generator will be empty:

>>> for i in gen: print i
>>>

The other answers are good for complicated scenarios. If you simply want to stream the items into a list:

x = list(generator)

For simple preprocessing, use list comprehensions:

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

If you just want to execute the generator without saving the results, you can skip variable assignment:

# no var assignment b/c we don't need what print() returns
[print(_) for _ in gen]

Don't do this if your generator is infinite (say, streaming items from the internet). The list construction is a blocking op that won't stop until the generator is empty.