【问题标题】:return and return None in a generator: PEP guidelines在生成器中返回和返回 None:PEP 指南
【发布时间】:2018-05-15 15:01:27
【问题描述】:

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

只要代码到达它们,生成器就会yield 值,除非遇到return 语句,在这种情况下它将停止迭代。但是,我看不到任何从生成器函数返回值的用例。本着这种精神,从 PEP 8 的角度来看,我不明白为什么用明确的 return None 结束这样的功能是有用的。换句话说,如果只有在 yield'ing 结束时才达到 return 表达式,为什么我们应该为生成器表达一个 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?

【问题讨论】:

  • 您误读了 PEP 8。一致性是在单个函数中,而不是在所有函数中。
  • 如果你偶尔会从同一个函数返回一个值或 None,请将其写为return None,而不仅仅是一个普通的return。对于生成器,应用相同的教训:yield None 与 yield,如果在其他地方你确实产生了一些价值。

标签: python generator yield pep


【解决方案1】:

您误读了 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 的返回值是 StopIteration 异常的 value 属性。因此,生成器可以使用return result 将结果返回给使用result = yield from generator 的代码:

>>> 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 &lt;something&gt; 退出并设置StopIteration.value。在整个生成器中始终使用return &lt;something&gt;,即使返回None:

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

【讨论】:

  • 啊,是的,我明白了。我对解释不好。所以一般来说,我们不会在生成器中使用返回值——但是为了遵守 PEP 8,我们仍然应该返回 None,对吗?
  • @BramVanroy:您确实在生成器中使用return,要么在该点退出生成器,要么退出并设置StopIteration.value 值。当您在第一种情况下使用return 时,只需使用return。无需添加None。 PEP-8 只说如果你在一个(生成器)函数中使用多个return 语句,那么它们都应该使用相同的模式。
  • @BramVanroy:所以如果你的生成器在一个地方使用return value,在另一个地方使用return,那么你会在另一个地方使用return None。
  • 这可能值得一提yield from。手动捕获StopIteration 并检查附加的异常value 是使用生成器返回值的一种不同寻常的方式,就像手动捕获StopIteration 通常是一种不同寻常的事情一样。
猜你喜欢
  • 2020-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-02
  • 2019-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多