生成器中的 return 和 return None:PEP 指南
return and return None in a generator: PEP guidelines
根据 PEP 8,我们应该在函数声明中保持一致,并确保它们都具有相同的 return 模式,即所有都应该 return 一个表达式,或者都不应该。但是,我不确定如何将其应用于生成器。
生成器将 yield
值,只要代码到达它们,除非遇到 return
语句,在这种情况下它将停止迭代。但是,我没有看到任何 returning 来自生成器函数的值的用例。本着这种精神,我不明白为什么用明确的 return None
结束这样的函数 - 从 PEP 8 的角度来看 - 是有用的。换句话说,如果 return 表达式仅在 yield'ing 结束时才达到,为什么我们应该用语言表达生成器的 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?
你误读了PEP8。 PEP8 声明:
Be consistent in return statements. Either all return statements in a function should return an expression, or none of them should.
(大胆强调我的)
您应该在单个函数中使用 return
的方式保持一致,而不是在整个项目中使用。
使用return
,它是函数中唯一的return
语句。
However, I don't see any use-case in which returning a value from a generator function can happen.
生成器的 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
的 return 值是 StopIteration
异常的 value
属性。因此,生成器可以 return 通过使用 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 ...
到 运行 包装generator 或 awaitable 并传递 return 值。
所以,从 PEP-8 的角度来看,对于生成器,有两种可能性:
您正在使用 return
提前退出生成器,比如在 if
循环中。使用return
,无需添加None
:
def foo():
while bar:
yield ham
if spam:
return
您正在使用 return <something>
退出 并且 设置 StopIteration.value
。在整个生成器中始终如一地使用 return <something>
, 即使 returning None
:
def foo():
for bar in baz:
yield bar
if spam:
return 'The bar bazzed the spam'
return None
根据 PEP 8,我们应该在函数声明中保持一致,并确保它们都具有相同的 return 模式,即所有都应该 return 一个表达式,或者都不应该。但是,我不确定如何将其应用于生成器。
生成器将 yield
值,只要代码到达它们,除非遇到 return
语句,在这种情况下它将停止迭代。但是,我没有看到任何 returning 来自生成器函数的值的用例。本着这种精神,我不明白为什么用明确的 return None
结束这样的函数 - 从 PEP 8 的角度来看 - 是有用的。换句话说,如果 return 表达式仅在 yield'ing 结束时才达到,为什么我们应该用语言表达生成器的 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?
你误读了PEP8。 PEP8 声明:
Be consistent in return statements. Either all return statements in a function should return an expression, or none of them should.
(大胆强调我的)
您应该在单个函数中使用 return
的方式保持一致,而不是在整个项目中使用。
使用return
,它是函数中唯一的return
语句。
However, I don't see any use-case in which returning a value from a generator function can happen.
生成器的 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
的 return 值是 StopIteration
异常的 value
属性。因此,生成器可以 return 通过使用 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 ...
到 运行 包装generator 或 awaitable 并传递 return 值。
所以,从 PEP-8 的角度来看,对于生成器,有两种可能性:
您正在使用
return
提前退出生成器,比如在if
循环中。使用return
,无需添加None
:def foo(): while bar: yield ham if spam: return
您正在使用
return <something>
退出 并且 设置StopIteration.value
。在整个生成器中始终如一地使用return <something>
, 即使 returningNone
:def foo(): for bar in baz: yield bar if spam: return 'The bar bazzed the spam' return None