我将函数f
定义为
def f(flag):
n = 10
if flag:
for i in range(n):
yield i
else:
return range(n)
但是,无论flag
是什么,f
都返回一个生成器:
>>> f(True)
<generator object f at 0x0000000003C5EEA0>
>>> f(False)
<generator object f at 0x0000000007AC4828>
如果我迭代返回的对象:
# prints normally
for i in f(True):
print(i)
# doesn't print
for i in f(False):
print(i)
看起来f(False)
返回了一个生成器,它已经被迭代过了。原因是什么?谢谢。
3条答案
按热度按时间pgvzfuti1#
包含
yield
语句的函数总是返回生成器对象。只有当你迭代那个生成器对象时,函数中的代码才会被执行,在此之前,函数中的代码不会被执行,Python * 不知道 * 你会返回。
注意,在生成器函数中使用
return
与在常规函数中使用return
具有 * 不同的语义 *;return
在这种情况下被简单地看作“在此退出生成器”;由于生成器只能通过yield
表达式产生值,因此丢弃返回值。看起来您想改用
yield from
:yield from
需要Python 3.3或更高版本。请参见
yield
表达式文档:在函数体中使用
yield
表达式会使该函数成为生成器。当调用生成器函数时,它返回一个称为生成器的迭代器。然后,该生成器控制生成器函数的执行。当调用生成器的一个方法时,执行开始。此时,执行继续到第一个
yield
表达式,在那里它再次挂起,并将expression_list的值返回给生成器的调用者。生成器上的迭代调用
generator.__next__()
方法,触发执行。如果你想在某个时候返回一个生成器,那么就不要在这个函数中使用
yield
,你可以用其他方法来生成生成器;例如,使用单独的函数,或者使用生成器表达式:现在,
f
中没有使用yield
,它也不再直接生成生成器对象,而是由生成器表达式(i for i in range(n))
生成,但条件是有条件的。qgelzfjb2#
您可以通过使用实际使用
yield
的嵌套函数来解决此问题:正如Martijn所指出的,任何包含
yield
的函数都将始终返回一个生成器对象,因此如果在某些情况下您希望f
的主体在调用f()
时实际执行,而不是仅在迭代时执行,则必须使用这种方法。concurrent.Futures.ProcessPoolExecutor
/concurrent.Futures.ThreadPoolExecutor
中的标准库示例方法map
使用此方法来确保future在map
被调用时立即提交,而不是仅在您尝试实际从中检索结果时才提交,例如:y0u0uwnf3#
生成器不会自动生成下一个yield值,除非您专门调用
我有一个名为“generate parameters”的生成器,一旦我这样做了,它就能正常工作: