Since Python 3.3, if a generator function returns a value, that becomes the value for the StopIteration exception that is raised. This can be collected a number of ways:
- The value of a
yield from
expression, which implies the enclosing function is also a generator.
- Wrapping a call to
next()
or .send()
in a try/except block.
However, if I'm simply wanting to iterate over the generator in a for loop - the easiest way - there doesn't appear to be a way to collect the value of the StopIteration exception, and thus the return value. Im using a simple example where the generator yields values, and returns some kind of summary at the end (running totals, averages, timing statistics, etc).
for i in produce_values():
do_something(i)
values_summary = ....??
One way is to handle the loop myself:
values_iter = produce_values()
try:
while True:
i = next(values_iter)
do_something(i)
except StopIteration as e:
values_summary = e.value
But this throws away the simplicity of the for loop. I can't use yield from
since that requires the calling code to be, itself, a generator. Is there a simpler way than the roll-ones-own for loop shown above?
Answer summary
Combining answers from @Chad S. and @KT, the simplest appears to turn my generator function into a class using the iterator protocol:
class ValueGenerator():
def __iter__(self):
yield 1
yield 2
# and so on
self.summary = {...}
vg = ValueGenerator()
for i in vg:
do_something(i)
values_summary = vg.summary
And @Ferdinand Beyer's answer is simplest if I can't refactor the value producer.
question from:
https://stackoverflow.com/questions/34073370/best-way-to-receive-the-return-value-from-a-python-generator 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…