On Thu, Feb 18, 2021 at 8:23 PM Luciano Ramalho firstname.lastname@example.org wrote:
Thanks for your reply, Guido.
On Fri, Feb 19, 2021 at 12:07 AM Guido van Rossum email@example.com wrote:
Reading the doc section you link to, it's pretty clear that
`@asyncio.coroutine` will be removed.
The *Note* right at the top of  says "Support for generator-based coroutines is deprecated and is scheduled for removal in Python 3.10."
But PEP 492  says:
"Since, internally, coroutines are a special kind of generators, every await is suspended by a yield somewhere down the chain of await calls"
If that part of PEP 492 is no longer accurate, then I have a couple of questions:
- What Python construct is to be used at the end of a chain of await
calls, if not of a generator-based coroutine decorated with `@types.coroutine` and using a `yield` expression in its body?
- Given that the sole purpose of `@types.coroutine` is to decorate
generator-based coroutines to become awaitable, will that decorator also be removed, along with "support for generator-based coroutines"?
It looks like types.coroutine will remain (it does not contain code to warn about deprecation like asyncio.coroutine does), but I don't think it is required to end a chain of coroutines -- it may have been an oversight that we did not start deprecating it. (But in any case it won't be supported by asyncio.)
At the end of the chain you can call the __await__() method which gives an iterator, and then you call next() or send() on that iterator. Each next()/send() call then represents an await step, and send() in general is used to provide an awaited result. Eventually this will raise StopIteration with a value indicating the ultimate result (the return value of the top-level async def).
The code used to "drive" a chain of await calls is called a trampoline. But writing a trampoline is not easy, and the only example I know of is asyncio's Task class, in particular its __step() method, which of course is beyond complicated because it has to handle so many special cases.