Noam
Noam

Reputation: 1804

Python 3.6 - filter with async function

This is pretty basic question but couldn't find a good information on it.

How can I use the built in filter function when the function I want to use to filter the elements is async?

Example:

import asyncio


async def not_one(item):
    if item == 1:
        await asyncio.sleep(1)  # Just to give an asyc feel.. 
        return False
    return True


async def main():
    org_list = [1, 2, 3]

    # IMPLEMENTATION #1 - WITHOUT USING FILTER
    without_one_list = []
    for item in org_list:
        is_one = await not_one(item)
        if is_one:
            without_one_list.append(item)

    print(without_one_list)  # [2, 3]

    # NOT WORKING #1 - not_one was never awaited
    without_one_list = list(filter(not_one, org_list))

    # NOT WORKING #2 - not a valid syntax
    without_one_list = list(filter(await not_one, org_list))

    # NOT WORKING #3 - not a valid syntax
    without_one_list = list(await filter(not_one, org_list))


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

How can I do what I want while using the filter function?

Thanks

Upvotes: 3

Views: 2993

Answers (1)

Adam.Er8
Adam.Er8

Reputation: 13393

in Python 3.6 you can use Asynchronous Generators

You should be able to define a simple async_filter on your own, like this:

async def async_filter(async_pred, iterable):
    for item in iterable:
        should_yield = await async_pred(item)
        if should_yield:
            yield item

then you can obtain a list by using Asynchronous Comprehensions:

import asyncio


async def not_one(item):
    if item == 1:
        await asyncio.sleep(1)  # Just to give an asyc feel..
        return False
    return True

async def async_filter(async_pred, iterable):
    for item in iterable:
        should_yield = await async_pred(item)
        if should_yield:
            yield item


async def main():
    org_list = [1, 2, 3]

    # IMPLEMENTATION #1 - WITHOUT USING FILTER
    without_one_list = []
    for item in org_list:
        is_one = await not_one(item)
        if is_one:
            without_one_list.append(item)

    print(without_one_list)  # [2, 3]

    without_one_list_async = [i async for i in async_filter(not_one, org_list)]
    print(without_one_list_async)
    print(without_one_list_async == without_one_list)


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())    

Output:

[2, 3]
[2, 3]
True

Upvotes: 5

Related Questions