在Python 2中,返回与函数定义中的yield一起出错。但对于Python 3.3中的这段代码
def f():
return 3
yield 2
x = f()
print(x.__next__())
没有错误,返回在带有yield的函数中使用。但是,当调用函数__next__
时,会抛出异常StopIteration。为什么没有返回值3
?这种回报是否被忽略了?
答案 0 :(得分:48)
这是Python 3.3中的一项新功能(作为评论说明,它甚至不适用于3.2)。与生成器中的return
长度相当于raise StopIteration()
非常相似,生成器中的return <something>
现在等同于raise StopIteration(<something>)
。因此,您看到的异常应打印为StopIteration: 3
,并且可以通过异常对象上的属性value
访问该值。如果生成器被委托使用(也是新的)yield from
语法,那么结果就是如此。有关详细信息,请参阅PEP 380。
def f():
return 1
yield 2
def g():
x = yield from f()
print(x)
# g is still a generator so we need to iterate to run it:
for _ in g():
pass
这会打印1
,但不打印2
。
答案 1 :(得分:24)
不会忽略返回值,但生成器只有 yield 值,return
只会结束生成器,在这种情况下就是早期。在这种情况下,推进生成器永远不会到达yield
语句。
每当迭代器到达要生成的值的“结束”时,必须引发StopIteration
。发电机也不例外。但是,从Python 3.3开始,任何return
表达式都将成为异常的值:
>>> def gen():
... return 3
... yield 2
...
>>> try:
... next(gen())
... except StopIteration as ex:
... e = ex
...
>>> e
StopIteration(3,)
>>> e.value
3
使用next()
函数推进迭代器,而不是直接调用.__next__()
:
print(next(x))
答案 2 :(得分:0)
此答案与问题完全无关,但对于在网络搜索后来到这里的人可能会派上用场。
这是一个小的辅助函数,它将所有最终的返回值转换为产生的值:
def generator():
yield 1
yield 2
return 3
def yield_all(gen):
while True:
try:
yield next(gen)
except StopIteration as e:
yield e.value
break
print([i for i in yield_all(generator())])
[1、2、3]
或作为装饰者:
import functools
def yield_all(func):
gen = func()
@functools.wraps(func)
def wrapper():
while True:
try:
yield next(gen)
except StopIteration as e:
yield e.value
break
return wrapper
@yield_all
def a():
yield 1
yield 2
return 3
print([i for i in a()])
[1、2、3]