z0r*_*z0r 6 python generator coroutine
鉴于Python协程:
def coroutine():
score = 0
for _ in range(3):
score = yield score + 1
Run Code Online (Sandbox Code Playgroud)
我想在一个像这样的简单循环中使用它:
cs = coroutine()
for c in cs:
print(c)
cs.send(c + 1)
Run Code Online (Sandbox Code Playgroud)
......我希望打印出来
1
3
5
Run Code Online (Sandbox Code Playgroud)
但实际上,我在线上得到了一个例外yield score + 1:
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
Run Code Online (Sandbox Code Playgroud)
如果我next手动调用,我可以让它工作:
c = next(cs)
while True:
print(c)
try:
c = cs.send(c + 1)
except StopIteration:
break
Run Code Online (Sandbox Code Playgroud)
但我不喜欢我需要使用try/except,因为发生器通常是如此优雅.
那么,有没有办法在没有明确处理的情况下使用像这样的有限协程StopIteration?我很高兴改变发生器和我迭代它的方式.
Martijn指出for循环和我的调用都是为了send推进迭代器.很公平.那么,为什么我不能在协程循环中使用两个yield语句来解决这个问题呢?
def coroutine():
score = 0
for _ in range(3):
yield score
score = yield score + 1
cs = coroutine()
for c in cs:
print(c)
cs.send(c + 1)
Run Code Online (Sandbox Code Playgroud)
如果我尝试,我会得到相同的错误,但send在线.
0
None
Traceback (most recent call last):
File "../coroutine_test.py", line 10, in <module>
cs.send(c + 1)
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
Run Code Online (Sandbox Code Playgroud)
我会尝试你的第二次尝试。首先,coroutine定义为:
def coroutine():
score = 0
for _ in range(3):
yield
score = yield score + 1
Run Code Online (Sandbox Code Playgroud)
该函数将输出您的1, 3, 5原始问题。
现在,让我们将for循环转换为while循环。
# for loop
for c in cs:
print(c)
cs.send(c + 1)
# while loop
while True:
try:
c = cs.send(None)
print(c)
cs.send(c + 1)
except StopIteration:
break
Run Code Online (Sandbox Code Playgroud)
现在,while如果我们在循环前面加上next(cs). 总共:
cs = coroutine()
next(cs)
while True:
try:
c = cs.send(None)
print(c)
cs.send(c + 1)
except StopIteration:
break
# Output: 1, 3, 5
Run Code Online (Sandbox Code Playgroud)
当我们尝试将其转换回 for 循环时,我们得到了相对简单的代码:
cs = coroutine()
next(cs)
for c in cs:
print(c)
cs.send(c + 1)
Run Code Online (Sandbox Code Playgroud)
这会输出1, 3, 5你想要的。问题是,在for循环的最后一次迭代中,cs已经耗尽,但又send被调用。那么,我们如何yield从生成器中得到另一个呢?让我们在最后添加一个...
def coroutine():
score = 0
for _ in range(3):
yield
score = yield score + 1
yield
cs = coroutine()
next(cs)
for c in cs:
print(c)
cs.send(c + 1)
# Output: 1, 3, 5
Run Code Online (Sandbox Code Playgroud)
最后一个示例按预期迭代,没有StopIteration例外。
现在,如果我们退一步,这一切都可以更好地写成:
def coroutine():
score = 0
for _ in range(3):
score = yield score + 1
yield # the only difference from your first attempt
cs = coroutine()
for c in cs:
print(c)
cs.send(c + 1)
# Output: 1, 3, 5
Run Code Online (Sandbox Code Playgroud)
注意 是如何yield移动的,以及 是如何next(cs)被移除的。