生成器中返回和返回无:PEP指南

时间:2018-05-15 15:01:28

标签: python generator yield pep

根据PEP 8,我们应该在函数声明中保持一致,并确保它们都具有相同的返回模式,即所有应该返回一个表达式,或者所有都不应该。但是,我不知道如何将其应用于发电机。

只要代码到达它们,生成器将yield值,除非遇到return语句,在这种情况下它将停止迭代。但是,我没有看到任何用例从生成器函数返回值的用例。本着这种精神,我不明白为什么从PEP 8的角度来看,用明确的return None来结束这样的功能是有用的。换句话说,如果仅在收益率结束时达到回报表达式,为什么我们应该用语言表示生成器的return语句?

示例:在以下代码中,我没有看到hello()如何用于将100分配给变量(因此使用return语句)。那么为什么PEP 8希望我们写一个return语句(无论是100还是None)。

def hello():
    for i in range(5):
      yield i

    return 100


h = [x for x in hello()]
g = hello()

print(h)    
# [0, 1, 2, 3, 4]
print(g)
# <generator object hello at 0x7fd2f285a7d8>
# can we ever get 100?

1 个答案:

答案 0 :(得分:2)

你误读了PEP8。 PEP8声明:

  

在回复陈述中保持一致。 函数中的所有return语句应该返回一个表达式,或者不应该返回任何表达式。

(大胆强调我的)

您应该与在单个函数中使用return的方式保持一致,而不是在整个项目中使用。

使用return,它是该函数中唯一的return语句。

  

但是,我没有看到任何可能发生从生成器函数返回值的用例。

生成器的返回值附加到引发的StopIteration异常:

>>> def gen():
...     if False: yield
...     return 'Return value'
...
>>> try:
...     next(gen())
... except StopIteration as ex:
...     print(ex.value)
...
Return value

这也是yield from产生价值的机制; yield from的返回值是value例外的StopIteration属性。因此,生成器可以使用result = yield from generator

使用return result将结果返回给代码
>>> def bar():
...     result = yield from gen()
...     print('gen() returned', result)
...
>>> next(bar(), None)
gen() returned Return value

此功能用于Python标准库;例如在asyncio库中,StopIteration的值用于传递Task个结果,而@coroutine装饰器使用res = yield from ...来运行包装的生成器或等待传递返回值。

因此,从PEP-8的角度来看,对于发电机而言,有两种可能性:

  • 您正在使用return提前退出生成器,例如在if的循环中。使用return,无需添加None

    def foo():
        while bar:
            yield ham
            if spam:
                return
    
  • 您正在使用return <something>退出设置StopIteration.value。在整个生成器中始终使用return <something>即使返回None

    def foo():
        for bar in baz:
            yield bar
            if spam:
                return 'The bar bazzed the spam'
        return None