Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Map, filter and itertools for composing asynchronous iterators

Does Python support functional-style operations on asynchronous iterators? I know that I can use map, filter and itertools to lazily transform and consume data coming from normal generators:

from itertools import accumulate, takewhile

def generator():
    a, b = 1, 1
    while True:
        yield a
        a, b = b, a + b

# create another iterator, no computation is started yet:
another_iterator = takewhile(lambda x: x < 100, accumulate(generator()))
# start consuming data:
print(list(another_iterator))
# [1, 2, 4, 7, 12, 20, 33, 54, 88]

Now, the same thing is not supported on Python 3.6's asynchronous generators/iterators because of course they do not implement the normal iterator protocol:

async def agenerator():
    a, b = 1, 1
    while True:
        yield a
        a, b = b, a + b

accumulate(agenerator())

TypeError: 'async_generator' object is not iterable

Is there some kind of async map or async itertools to achieve the similarly lazy behaviour in Python 3.6/3.7?

like image 341
Norrius Avatar asked May 31 '18 12:05

Norrius


1 Answers

Most full asynchronous version of itertools I saw is aiostream module. Your example will be:

import asyncio
from aiostream.stream import takewhile, accumulate, list as alist


async def agenerator():
    a, b = 1, 1
    while True:
        yield a
        a, b = b, a + b


async def main():
    another_iterator = takewhile(
        accumulate(agenerator()),
        lambda x: x < 100, 
    )

    res = await alist(another_iterator)

    print(res)


loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
like image 84
Mikhail Gerasimov Avatar answered Oct 31 '22 14:10

Mikhail Gerasimov