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
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4