什么时候使用return(产量)?

lai*_*e9m 22 python generator

很长一段时间我都不知道你不能return在收益率声明面前.但实际上你可以:

def gen():
    return (yield 42)
Run Code Online (Sandbox Code Playgroud)

这类似于

def gen():
    yield 42
    return
Run Code Online (Sandbox Code Playgroud)

我能想到的唯一用法是将发送的值附加到StopIteration:pep-0380

生成器中的return expr导致从生成器退出时引发StopIteration(expr).

def gen():
    return (yield 42)

g = gen()
print(next(g))  # 42
try:
    g.send('AAAA')
except StopIteration as e:
    print(e.value)  # 'AAAA'
Run Code Online (Sandbox Code Playgroud)

但这也可以使用额外的变量来完成,这更明确:

def gen():
    a = yield 42
    return a

g = gen()
print(next(g))
try:
    g.send('AAAA')
except StopIteration as e:
    print(e.value)  # 'AAAA'
Run Code Online (Sandbox Code Playgroud)

所以它似乎return (yield xxx)只是一种语法糖.我错过了什么吗?

小智 8

在生成器内部,表达式(yield 42)将产生值42,但它也返回一个值,如果使用则为None,如果使用则返回next(generator)给定值generator.send(value).

正如你所说,你可以使用一个中间值来获得相同的行为,不是因为这是语法糖,而是因为yield表达式实际上是返回你发送它的值.

你也可以这样做

def my_generator():
    return (yield (yield 42) + 10)
Run Code Online (Sandbox Code Playgroud)

如果我们调用它,使用调用序列:

g = my_generator()
print(next(g))
try:
    print('first response:', g.send(1))
    print('Second response:', g.send(22))
    print('third response:', g.send(3))
except StopIteration as e:
    print('stopped at', e.value)
Run Code Online (Sandbox Code Playgroud)

首先我们得到42的输出,并且生成器基本上暂停在你可以描述的状态: return (yield <Input will go here> + 10),如果我们然后调用g.send(1)我们得到输出11.并且生成器现在处于状态: return <Input will go here>,然后发送g.send(22)将抛出StopIteration(22),因为返回的方式在生成器中处理.所以你永远不会因为异常而进入第三次发送.

我希望这个例子让我们更清楚地知道yield生成器是如何工作的,以及为什么语法return (yield something)没有什么特别或异国情调,并且正如你所期望的那样.

至于字面问题,你什么时候会这样做?好吧,当你想要产生某些东西,然后返回一个StopIteration回显发送给发生器的用户的输入.因为这实际上是代码所说的内容.我希望这种行为很少被人想要.