在Python 3.3中将生成器与yield一起返回

scd*_*dmb 48 python generator python-3.x

在Python 2中,当函数定义中的return与yield一起时,出现了错误.但对于Python 3.3中的这段代码

def f():
  return 3
  yield 2

x = f()
print(x.__next__())
Run Code Online (Sandbox Code Playgroud)

没有错误,返回用于带有yield的函数.但是,当__next__调用该函数时,会抛出异常StopIteration.为什么不只是返回价值3?这种回报是否被忽略了?

小智 52

这是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
Run Code Online (Sandbox Code Playgroud)

这打印1,但不是2.


Mar*_*ers 27

返回值不会被忽略,但生成器只会产生值,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
Run Code Online (Sandbox Code Playgroud)

使用该next()函数来推进迭代器,而不是.__next__()直接调用:

print(next(x))
Run Code Online (Sandbox Code Playgroud)

  • 带有值的`return`不会被忽略,它是语法错误(在3.2及更低版本中)或未被忽略(在3.3及更高版本中)。 (2认同)
  • 实际上,“回报”并不能替代“收益”,但它的价值不是“没有”。它可以作为异常对象的属性来使用,“ yield from”可以方便地访问它。 (2认同)