async enumeration - possible?

Chris Angelico rosuav at gmail.com
Wed Nov 30 03:20:15 EST 2016


On Wed, Nov 30, 2016 at 7:10 PM, Ian Kelly <ian.g.kelly at gmail.com> wrote:
> On Tue, Nov 29, 2016 at 8:22 PM, Chris Angelico <rosuav at gmail.com> wrote:
>> Interestingly, I can't do that in a list comp:
>>
>>>>> [x async for x in aiterable]
>>   File "<stdin>", line 1
>>     [x async for x in aiterable]
>>            ^
>> SyntaxError: invalid syntax
>>
>> Not sure why.
>
> Because you tried to use an async comprehension outside of a coroutine.
>
> py> [x async for x in y]
>   File "<stdin>", line 1
>     [x async for x in y]
>            ^
> SyntaxError: invalid syntax
> py> async def foo():
> ...     [x async for x in y]
> ...
>
> The same is true for async generator expressions. The documentation is
> clear that this is illegal for the async for statement:
>
> https://docs.python.org/3.6/reference/compound_stmts.html#the-async-for-statement

Hmm. The thing is, comprehensions and generators are implemented with
their own nested functions. So I would expect that their use of async
is independent of the function they're in. But maybe we have a bug
here?

>>> async def spam():
...     def ham():
...         async for i in x:
...             pass
...
>>> def ham():
...     async for i in x:
  File "<stdin>", line 2
    async for i in x:
            ^
SyntaxError: invalid syntax
>>> def ham():
...     async def spam():
...         async for i in x:
...             pass
...
>>>

Clearly the second one is correct to throw SyntaxError, and the third
is correctly acceptable. But the first one, ISTM, should be an error
too.

> Yeah, that's what I would expect. (x async for x in foo) is
> essentially a no-op, just like its synchronous equivalent; it takes an
> asynchronous iterator and produces an equivalent asynchronous
> iterator. Meanwhile, list() can't consume an async iterator because
> the list constructor isn't a coroutine. I don't think it's generally
> possible to "synchronify" an async iterator other than to materialize
> it. E.g.:
>
> def alist(aiterable):
>     result = []
>     async for value in aiterable:
>         result.append(value)
>     return result
>
> And I find it a little disturbing that I actually can't see a better
> way to build a list from an async iterator than that.

Oh. Oops. That materialization was exactly what I intended to happen
with the comprehension. Problem: Your version doesn't work either,
although I think it probably _does_ work if you declare that as "async
def alist".

Shows you just how well I understand Python's asyncness, doesn't it?

ChrisA



More information about the Python-list mailing list