[Python-Dev] PEP 492 vs. PEP 3152, new round
Yury Selivanov
yselivanov.ml at gmail.com
Fri Apr 24 23:51:30 CEST 2015
Lukasz,
On 2015-04-24 5:37 PM, Łukasz Langa wrote:
>
>> (Though maybe we should consider `await for` and `await with`? That would have the advantage of making it easy to scan for all suspension points by searching for /await/. But being a verb it doesn't read very well.)
> I’m on the fence here.
>
> OT1H, I think “await for something in a_container” and “await with a_context_manager():” also read pretty well. It’s also more consistent with being the one way of finding “yield points”.
>
> OTOH, “await with a_context_manager():” suggests the entire statement is awaited on, which is not true. “async with” is more opaque in this way, it simply states “there are going to be implementation-specific awaits inside”. So it’s more consistent with “async def foo()”.
This. I also think of 'await with' as I'm awaiting on the whole
statement. And I don't even know how to interpret that.
>> 6. StopAsyncException
>>
>> I'm not sure about this. The motivation given in the PEP seems to focus on the need for `__anext__` to be async. But is this really the right pattern? What if we required `ait.__anext__()` to return a future, which can either raise good old `StopIteration` or return the next value from the iteration when awaited? I'm wondering if there are a few alternatives to be explored around the async iterator protocol still.
> So are you suggesting to pass the returned value in a future? In this case the future would need to be passed to __anext__, so the Cursor example from the PEP would look like this:
>
> class Cursor:
> def __init__(self):
> self.buffer = collections.deque()
>
> def _prefetch(self):
> ...
>
> async def __aiter__(self):
> return self
>
> async def __anext__(self, fut):
> if not self.buffer:
> self.buffer = await self._prefetch()
> if self.buffer:
> fut.set_result(self.buffer.popleft())
> else:
> fut.set_exception(StopIteration)
>
> While this is elegant, my concern is that one-future-per-iteration-step might be bad for performance.
>
> Maybe consider the following. The `async def` syntax decouples the concept of a coroutine from the implementation. While it’s still based on generators under the hood, the user no longer considers his “async function” to be a generator or conforming to the generator protocol. From the user’s perpective, it’s obvious that the return below means something different than the exception:
>
> async def __anext__(self):
> if not self.buffer:
> self.buffer = await self._prefetch()
> if not self.buffer:
> raise StopIteration
> return self.buffer.popleft()
>
> So, the same way we added wrapping in RuntimeErrors for generators in PEP 479, we might add transparent wrapping in a _StopAsyncIteration for CO_COROUTINE.
FWIW I have to experiment more with the reference implementation,
but at the moment I'm big -1 on touching StopIteration for
coroutines. It's used for too many things.
Thanks!
Yury
More information about the Python-Dev
mailing list