python接收return值,从python生成器接收'return'值的最佳方法

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.

解决方案

You can think of the value attribute of StopIteration (and arguably StopIteration itself) as implementation details, not designed to be used in "normal" code.

Have a look at PEP 380 that specifies the yield from feature of Python 3.3: It discusses that some alternatives of using StopIteration to carry the return value where considered.

Since you are not supposed to get the return value in an ordinary for loop, there is no syntax for it. The same way as you are not supposed to catch the StopIteration explicitly.

A nice solution for your situation would be a small utility class (might be useful enough for the standard library):

class Generator:

def __init__(self, gen):

self.gen = gen

def __iter__(self):

self.value = yield from self.gen

This wraps any generator and catches its return value to be inspected later:

>>> def test():

... yield 1

... return 2

...

>>> gen = Generator(test())

>>> for i in gen:

... print(i)

...

1

>>> print(gen.value)

2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值