[Python-ideas] PEP 525: Asynchronous Generators

Yury Selivanov yselivanov.ml at gmail.com
Sat Aug 6 12:51:26 EDT 2016


Hi Nick,

On 2016-08-06 4:28 AM, Nick Coghlan wrote:

> On 6 August 2016 at 01:11, Andrew Svetlov <andrew.svetlov at gmail.com> wrote:
>> Honestly I personally don't feel a need for two-way generators with
>> `asend()`/`athrow()` but as Yury explained he need them internally for
>> `anext`/`aclose` anyway.
> Even if asend()/athrow() are cheap from an implementation perspective,
> they're *not* necessarily cheap from a "cognitive burden of learning
> the API" perspective. We know what send() and throw() on generators
> are for: implementing coroutines. However, we also know that layering
> that on top of the generator protocol turned out to be inherently
> confusing, hence PEP 492 and async/await.
>
> So if we don't have a concrete use case for "coroutine coroutines"
> (what does that even *mean*?), we shouldn't add asend()/athrow() just
> because it's easy to do so.

One immediate use case that comes to mind is
@contextlib.asynccontextmanager

Essentially this:

   @contextlib.asynccontextmanager
   async def ctx():
     resource = await acquire()
     try:
       yield resource
     finally:
       await release(resource)

I'm also worrying that in order to do similar things people will
abuse "agen.__anext__().send()" and "agen.__anext__().throw()".
And this is a very error-prone thing to do.  For example, in
asyncio code, you will capture yielded Futures that the
generator is trying to await on (those yielded futures
have to be captured by the running Task object instead).

"asend" and "athrow" know about iteration protocol and can see
the "wrapped" yielded objects, hence they can iterate the
generator correctly and reliably.

I think Nathaniel Smith (CC-ed) had a few more use cases for
asend/athrow.


>
> If we wanted to hedge our bets, we could expose them as _asend() and
> _athrow() initially, on the grounds that doing so is cheap, and we're
> genuinely curious to see if anyone can find a non-toy use case for
> them. But we should be very reluctant to add them to the public API
> without a clear idea of why they're there.

I think we should decide if we want to expose them at all.
If we're in doubt, let's not do that at all.  Exposing them
with a "_" prefix doesn't free us from maintaining backwards
compatibility etc.

You're completely right about the increased "cognitive burden
of learning the API".  On the other hand, send() and throw()
for sync generators were designed for power users; most
Python developers don't even know that they exist.  I think
we can view asend() and athrow() similarly.

Thank you,
Yury




More information about the Python-ideas mailing list