Make synchronous generator from an asynchronous generator

Ian Kelly ian.g.kelly at gmail.com
Fri Mar 16 11:55:36 EDT 2018


On Thu, Mar 15, 2018 at 1:35 PM, Julien Salort <listes at salort.eu> wrote:
> Because I wanted to keep the synchronous function for scripts which used it, without unnecessarily duplicating the code, I built also a synchronous function from this new asynchronous one, like that:
>
> def acquire_to_files(self, *args, **kwargs):
>     loop = asyncio.get_event_loop()
>     loop.run_until_complete(self.acquire_to_files_async(*args, **kwargs))
>     loop.close()

Note that this function can't be called more than once, because it
closes the event loop at the end. Next time you call it it will get
the closed event loop and try to schedule on it and then raise an
exception because it's closed.

> So far, it works fine. I am quite happy.
>
> I can await acquire_to_files_async in situations where I need concurrency, and call acquire_to_files in situations where I don't, and no code is duplicated.
>
>
> Now I wish to do the same game with a generator (which happens to be called by the acquire_to_files_async function). So I made it into an asynchronous generator, and it works as expected.
>
> My problem: how do I proceed if I wish to build a synchronous generator from this asynchronous generator ?
>
> (for situations where concurrency is not needed)
>
> i.e. what is the equivalent of the above snippet for generators ?

Well, it's not pretty, but this seems to work:

async def agen():
    yield 1
    yield 2
    yield 3

def gen():
    loop = asyncio.get_event_loop()
    ait = agen().__aiter__()
    try:
        while True:
            yield loop.run_until_complete(ait.__anext__())
    except StopAsyncIteration:
        return

py> list(gen())
[1, 2, 3]

It would take some additional code if you wanted to wire up
gen().send() and gen().throw() to work as well, but it should be
doable.



More information about the Python-list mailing list