Run code on coroutine close()

心已入冬 提交于 2021-02-08 03:50:35

问题


I am writing code that uses coroutines heavily, and I want reliable behavior on shutdown.

Say I have a coroutine and a context manager:

from contextlib import contextmanager

@contextmanager
def print_context_manager(text):
    print("Enter", text)
    yield
    print("Exit", text)

def coro():
    with print_context_manager("coro"):
        while True:
            print("Loop", (yield))

I could use it like this:

c = coro()
next(c)
c.send("Hello ")
c.send("World!")
c.close()

Unfortunately, as far as I can tell, there is no way to execute my own code on c.close(). In particular the context manager in coroutine never prints "Exit coro"

What's the point of context managers in coroutines? Do I have to manually come up with a way to signal the end of a stream? What's the point of close() then?

See this example: https://repl.it/M0XI/0


回答1:


Your context manager has a bug. Correct it, and it will automatically perform cleanup when the coroutine is closed.

Closing a coroutine works by raising GeneratorExit at the point where the coroutine is suspended. If the code in the with raises an exception, @contextlib.contextmanager raises that exception at the point of the yield. Your context manager doesn't deal with that, so the exception prevents the cleanup from running.

You need to wrap the yield in a try-finally and do cleanup in the finally if you want the cleanup to run even on an exception:

@contextmanager
def print_context_manager(text):
    print("Enter", text)
    try:
        yield
    finally:
        print("Exit", text)


来源:https://stackoverflow.com/questions/46677432/run-code-on-coroutine-close

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!