carver
carver

Reputation: 2349

Aggregating an async generator to a tuple

In trying to aggregate the results from an asynchronous generator, like so:

async def result_tuple():
    async def result_generator():
        # some await things happening in here
        yield 1
        yield 2
    return tuple(num async for num in result_generator())

I get a

TypeError: 'async_generator' object is not iterable

when executing the async for line.

But PEP 530 seems to suggest that it should be valid:

Asynchronous Comprehensions

We propose to allow using async for inside list, set and dict comprehensions. Pending PEP 525 approval, we can also allow creation of asynchronous generator expressions.

Examples:

  • set comprehension: {i async for i in agen()};
  • list comprehension: [i async for i in agen()];
  • dict comprehension: {i: i ** 2 async for i in agen()};
  • generator expression: (i ** 2 async for i in agen()).

What's going on, and how can I aggregate an asynchronous generator into a single tuple?

Upvotes: 9

Views: 5237

Answers (1)

carver
carver

Reputation: 2349

In the PEP excerpt, the comprehensions are listed side-by-side in the same bullet list, but the generator expression is very different from the others.

There is no such thing as a "tuple comprehension". The argument to tuple() makes an asynchronous generator:

tuple(num async for num in result_generator())

The line is equivalent to tuple(result_generator()). The tuple then tries to iterate over the generator synchronously and raises the TypeError.

The other comprehensions will work, though, as the question expected. So it's possible to generate a tuple by first aggregating to a list, like so:

async def result_tuple():
    async def result_generator():
        # some await things happening in here
        yield 1
        yield 2
    return tuple([num async for num in result_generator()])

Upvotes: 6

Related Questions