[Python-ideas] PEP 525: Asynchronous Generators
Yury Selivanov
yselivanov.ml at gmail.com
Fri Aug 5 19:25:29 EDT 2016
On 2016-08-05 4:51 PM, Sven R. Kunze wrote:
> On 04.08.2016 17:17, Yury Selivanov wrote:
>>
>>> From your answer to Stefan, I get the impression that the reason why
>>> we actual need all those a* methods (basically a duplication of the
>>> existing gen protocol), is the fact that normal generators can be
>>> converted to coroutines. That means, 'yield' still can be used in
>>> both ways.
>>>
>>> So, it's a technical symptom of the backwards-compatibility rather
>>> than something that cannot be avoided by design. Is this correct?
>>>
>>
>> async/await in Python is implemented on top of the generator
>> protocol. Any 'await' is either awaiting on a coroutine or on a
>> Future-like object. Future-like objects are defined by implementing
>> the __await__ method, which should return a generator.
>>
>> So coroutines and generators are very intimately tied to each other,
>> and that's *by design*.
>>
>> Any coroutine that iterates over an asynchronous generator uses the
>> generator protocol behind the scenes. So we have to multiplex the
>> async generaotor's "yields" into the generator protocol in such a
>> way, that it stays isolated, and does not interfere with the "yields"
>> that drive async/await.
>
> Yes, that is how I understand it as well. So, all this complexity
> stems from the intertwining of generators and coroutines.
>
> I am wondering if loosening the tie between the two could make it all
> simpler; even for you. (Not right now, but maybe later.)
Unfortunately, the only way to "loosen the tie" is to re-implement
generator protocol for coroutines (make them a separate thing). Besides
breaking backwards compatibility with the existing Python code that uses
@coroutine decorator and 'yield from' syntax, it will also introduce a
ton of work.
>
>
>
>>
>>> If it's correct, would you think it would make sense to get rid of
>>> the a* in a later iteration of the async capabilities of Python? So,
>>> just using the normal generator protocol again?
>>
>> Because async generators will contain 'await' expressions, we have to
>> have a* methods (although we can name them without the "a" prefix,
>> but I believe that would be confusing for many users).
>>
>
> I think that is related to Stefan's question here. I cannot speak for
> him but it seems to me the confusion is actually the other way around.
>
> Coming from a database background, I prefer redundant-free data
> representation. The "a" prefix encodes the information "that's an
> asynchronous generator" which is repeated several times and thus is
> redundant.
>
> Another example: when writing code for generators and checking for the
> "send" method, I would then need to check for the "asend" method as
> well. So, I would need to touch that code although it even might not
> have been necessary in the first place.
>
> I don't want to talk you out of the "a" prefix, but I get the feeling
> that the information "that's asynchronous" should be provided as a
> separate attribute. I believe it would reduce confusion, simplify
> duck-typing and flatten the learning curve. :)
Thing is you can't write one piece of code that will accept any type of
generator (sync or async).
* send, throw, close, __next__ methods for sync generators, they are
synchronous.
* send, throw, close, __next__ methods for async generators, they
*require* to use 'await' on them. There is no way to make them
"synchronous", because you have awaits in async generators.
Because of the above, duck-typing simply isn't possible.
The prefix is there to make people aware that this is a completely
different API, even though it looks similar.
Thank you,
Yury
More information about the Python-ideas
mailing list