我阅读了有关协程A Curious Course on Coroutines and Concurrency
的简短演示def countdown(n):
print("Counting down from", n)
while n > 0:
yield n
n -= 1
#why it stop?
x = countdown(10)
#no output was produced
第一次调用时我没有打印结果。
In [10]: x
Out[10]: <generator object countdown at 0x1036e4228>
但应该
In [14]: next(x)
Out[14]: Counting down from 10
In [15]: next(x)
Out[15]: 1
In [16]: next(x)
为什么在我调用函数print("Counting down from", n)
时不直接执行countdown()
。
我认为Counting down from 10
应该以任何收益执行,这是一个顺序过程。
print("Counting down from", n)
正在运行什么,我知道
do something yield
收益将停止前面的行动,
但是在倒计时示例中,yield
如何通过穿透while循环来停止print("Counting down from", n)
答案 0 :(得分:1)
如果我正确理解了您的问题,那么您希望在致电Counting down from 10
时立即看到countdown(10)
文本已打印出来。但这反映了对生成器功能如何工作的误解。
yield
表达式不能仅仅中断普通函数的控制流程。相反,任何在其中任何位置包含yield
的函数都将成为生成器函数,其工作原理与普通函数不同。
调用生成器函数时,其代码均不会立即运行。取而代之的是,Python只是创建了一个生成器对象,该对象封装了函数调用的状态(起初它只会记录您处于函数的最顶端,而函数尚未开始运行)。生成器对象是返回给调用者的对象。
只有在生成器对象上调用next
后,函数的代码才开始运行。它会一直运行到出现yield
表达式为止,并且yield
返回的是next
ed的值。正在运行的函数的状态保存为生成器对象的一部分,并且保持暂停状态,直到您再次对其调用next
。
要注意的重要一点是,生成器对象永远不会在yield
之前运行,直到外部代码完成了产生的值并要求另一个值为止。我们之所以使用生成器函数是因为它们很懒!
这是一个简单的脚本,它可以比示例生成器尝试做更多有用的事情来帮助您更好地理解它的工作原理:
import time
def generator_function():
print("generator start")
yield 1
print("generator middle")
yield 2
print("generator end")
print("creating the generator")
generator_object = generator_function()
print("taking a break")
time.sleep(1)
print("getting first value")
val1 = next(generator_object)
print("got", val1)
print("taking a break")
time.sleep(1)
print("getting second value")
val2 = next(generator_object)
print("got", val2)
print("taking a break")
time.sleep(1)
print("try getting a third value (it won't work)")
try:
val3 = next(generator_object) # note, the assignment never occurs, since next() raises
print("got", val3) # this line won't ever be reached
except Exception as e:
print("got an exception instead of a value:", type(e))
生成器的打印语句将始终出现在外部代码的“获取”和“获取”消息之间。