在 Python 中重构协程
我想通过在其他功能/coroutine中移动其一些代码来重构Coroutine。但是我需要在包含的coroutine中检索其最后一个供稿,而且我不知道如何正确地做到这一点。
这是一个简单的coroutine示例。
def coroutine():
"""Yield a string containing the number sent. If 5 is sent, block for 5 turns."""
feed = yield 0
while True:
if feed == 5:
for i in range(5, 0, -1):
feed = yield f"Blocked for {i} turns"
feed = yield f"Received {feed}"
if __name__ == "__main__":
my_coroutine = coroutine()
next(my_coroutine) # Init the coroutine
# Print the coroutine results for inputs from 0 to 14
for j in range(15):
print(f"{j} -> {my_coroutine.send(j)}")
我期望(并获得)的结果是
0 -> Received 0
1 -> Received 1
2 -> Received 2
3 -> Received 3
4 -> Received 4
5 -> Blocked for 5 turns
6 -> Blocked for 4 turns
7 -> Blocked for 3 turns
8 -> Blocked for 2 turns
9 -> Blocked for 1 turns
10 -> Received 10
11 -> Received 11
12 -> Received 12
13 -> Received 13
14 -> Received 14
,我想通过将可重复使用的零件移至coroutine wait_for_five_turns
来改进代码:
def wait_for_five_turns():
"""Block for 5 turns."""
for i in range(5, 0, -1):
feed = yield f"Blocked for {i} turns"
def coroutine():
"""Yield a string containing the number sent. If 5 is sent, block for 5 turns."""
feed = yield 0
while True:
if feed == 5:
yield from wait_for_five_turns()
# "feed" is not up to date ! And it's logic, but bothersome.
feed = yield f"Received {feed}"
0 -> Received 0
1 -> Received 1
2 -> Received 2
3 -> Received 3
4 -> Received 4
5 -> Blocked for 5 turns
6 -> Blocked for 4 turns
7 -> Blocked for 3 turns
8 -> Blocked for 2 turns
9 -> Blocked for 1 turns
10 -> Received 5 <----- Not what I want
11 -> Received 11
12 -> Received 12
13 -> Received 13
14 -> Received 14
有没有办法检索正确的feed值? 还是更好的重构方法? 祝你今天过得愉快。
I want to refactor a coroutine by moving some of its code in another function/coroutine. But I would need to retrieve its last feed in the containing coroutine, and I've got no idea how to properly do that.
Here's an example with a simpler coroutine.
def coroutine():
"""Yield a string containing the number sent. If 5 is sent, block for 5 turns."""
feed = yield 0
while True:
if feed == 5:
for i in range(5, 0, -1):
feed = yield f"Blocked for {i} turns"
feed = yield f"Received {feed}"
if __name__ == "__main__":
my_coroutine = coroutine()
next(my_coroutine) # Init the coroutine
# Print the coroutine results for inputs from 0 to 14
for j in range(15):
print(f"{j} -> {my_coroutine.send(j)}")
The result that I expect (and get) is
0 -> Received 0
1 -> Received 1
2 -> Received 2
3 -> Received 3
4 -> Received 4
5 -> Blocked for 5 turns
6 -> Blocked for 4 turns
7 -> Blocked for 3 turns
8 -> Blocked for 2 turns
9 -> Blocked for 1 turns
10 -> Received 10
11 -> Received 11
12 -> Received 12
13 -> Received 13
14 -> Received 14
Now, I want to improve my code by moving the reusable part to a coroutine wait_for_five_turns
:
def wait_for_five_turns():
"""Block for 5 turns."""
for i in range(5, 0, -1):
feed = yield f"Blocked for {i} turns"
def coroutine():
"""Yield a string containing the number sent. If 5 is sent, block for 5 turns."""
feed = yield 0
while True:
if feed == 5:
yield from wait_for_five_turns()
# "feed" is not up to date ! And it's logic, but bothersome.
feed = yield f"Received {feed}"
0 -> Received 0
1 -> Received 1
2 -> Received 2
3 -> Received 3
4 -> Received 4
5 -> Blocked for 5 turns
6 -> Blocked for 4 turns
7 -> Blocked for 3 turns
8 -> Blocked for 2 turns
9 -> Blocked for 1 turns
10 -> Received 5 <----- Not what I want
11 -> Received 11
12 -> Received 12
13 -> Received 13
14 -> Received 14
Is there a way to retrieve the correct value of feed ?
Or maybe a better way to refactor ?
Have a nice day.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
也可以从Coroutine返回值。在当前的示例中,这将是:
这将打印正确的预期输出:
我使用了错误的类型注释(发电机类型提示的第三个元素),这使我认为Coroutine只能返回。
有关信息,这是这两个功能的类型提示:
It possible to also return a value from a coroutine. In the the current example, this will be :
This prints the correct expected output :
I was using a wrong type annotation (3rd element of the Generator type hint) that made me think a coroutine could only return None.
For info, here's the type hint for those two functions :