peo*_*les 5 python yield generator coroutine python-3.x
我正在python 3中尝试生成器,并编写了这个相当人为的生成器:
def send_gen():
print(" send_gen(): will yield 1")
x = yield 1
print(" send_gen(): sent in '{}'".format(x))
# yield # causes StopIteration when left out
gen = send_gen()
print("yielded {}".format(gen.__next__()))
print("running gen.send()")
gen.send("a string")
Run Code Online (Sandbox Code Playgroud)
输出:
send_gen(): will yield 1
yielded 1
running gen.send()
send_gen(): sent in 'a string'
Traceback (most recent call last):
File "gen_test.py", line 12, in <module>
gen.send("a string")
StopIteration
Run Code Online (Sandbox Code Playgroud)
因此gen.__next__()到达该行x = yield 1并产生1。我认为x将被分配给None,然后gen.send()将查找下一个 yield因为x = yield 1“已使用”的语句,然后得到一个StopIteration。
相反,什么似乎已经发生的是,x被发送“的字符串”,这是印刷,然后再蟒蛇试图寻找下一个yield,并得到一个StopIteration。
所以我试试这个:
def send_gen():
x = yield 1
print(" send_gen(): sent in '{}'".format(x))
gen = send_gen()
print("yielded : {}".format(gen.send(None)))
Run Code Online (Sandbox Code Playgroud)
输出:
yielded : 1
Run Code Online (Sandbox Code Playgroud)
但是现在没有错误了。分配给后,send()似乎没有尝试寻找下 yield一条语句。xNone
为什么行为略有不同?这与我如何启动发电机有关吗?
行为没有什么不同;yield在第二种设置中,您从未超越生成器中的第一个表达式。请注意,StopIteration是不是一个错误 ; 这是正常的行为,只要发电机结束,就会发出预期的信号。在第二个示例中,您从未到达生成器的末端。
每当生成器到达yield表达式时,执行就在那里暂停,直到恢复生成器之后,表达式才能在生成器内部不产生任何东西。任一gen.__next__()或gen.send()将从该点既恢复执行,与yield表达任一制造在由传递的值gen.send(),或None。你可以看到gen.__next__()作为一个gen.send(None)没有什么帮助。在这里有一点要明白的是,gen.send()有yield返回值SENT 第一,并随后发电机继续到下一个yield。
因此,考虑到您的第一个示例生成器,将发生以下情况:
gen = send_gen()创建生成器对象。代码在函数的最上方暂停,不执行任何操作。
您可以致电gen.__next__()或gen.send(None); 生成器启动并执行直到第一个yield表达式:
print(" send_gen(): will yield 1")
yield 1
Run Code Online (Sandbox Code Playgroud)
现在执行暂停。该gen.__next__()或gen.send(None)电话现在回到1,该值产生的yield 1。由于生成器现在已暂停,x = ...因此无法进行分配!只有在再次恢复生成器时才会发生这种情况。
你叫gen.send("a string")你的第一个例子,不作任何在第二个电话。因此,对于第一个示例,现在恢复了generator函数:
x = <return value of the yield expression> # 'a string' in this case
print(" send_gen(): sent in '{}'".format(x))
Run Code Online (Sandbox Code Playgroud)
现在函数结束,因此StopIteration引发。
因为在第二个示例中您从未恢复过生成器,所以没有达到生成器的末尾并且不会StopIteration引发异常。
请注意,由于生成器从函数的顶部开始,因此此时没有yield表达式返回您发送的内容,gen.send()因此第一个gen.send()值必须始终为,None否则将引发异常。最好使用显式gen.__next__()(或next(gen)函数调用)来“生成”生成器,以使其在第一个yield表达式处暂停。
| 归档时间: |
|
| 查看次数: |
1617 次 |
| 最近记录: |