how can I asynchronously map/filter an asynchronous iterable?
You can't use yield inside coroutines. To implement your idea, only way I see is to implement Asynchronous Iterator. If I'm right, something like that:
class MapFilter:
def __init__(self, aiterable, p, func):
self.aiterable = aiterable
self.p = p
self.func = func
async def __aiter__(self):
return self
async def __anext__(self):
while True:
payload = await self.aiterable.__anext__() # StopAsyncIteration would be raise here on no new values
if self.p(payload):
return self.func(payload)
Let's test it. Here's complete example with helper arange
class (I took it from here):
import asyncio
class arange:
def __init__(self, n):
self.n = n
self.i = 0
async def __aiter__(self):
return self
async def __anext__(self):
i = self.i
self.i += 1
if self.i <= self.n:
await asyncio.sleep(0) # insert yield point
return i
else:
raise StopAsyncIteration
class MapFilter:
def __init__(self, aiterable, p, func):
self.aiterable = aiterable
self.p = p
self.func = func
async def __aiter__(self):
return self
async def __anext__(self):
while True:
payload = await self.aiterable.__anext__()
if self.p(payload):
return self.func(payload)
async def main():
aiterable = arange(5)
p = lambda x: bool(x>2)
func = lambda x: x*2
async for i in MapFilter(aiterable, p, func):
print(i)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Output:
6
8
A recently published PEP draft (PEP 525), whose support is scheduled for Python 3.6, proposes to allow Asynchronous Generators with the same syntax you came up with.
Meanwhile, you can also use the asyncio_extras
library mentioned by CryingCyclops in its comment if you don't want to deal with the asynchronous iterator boilerplate.
From the docs:
@async_generator
async def mygenerator(websites):
for website in websites:
page = await http_fetch(website)
await yield_async(page)
async def fetch_pages():
websites = ('http://foo.bar', 'http://example.org')
async for sanitized_page in mygenerator(websites):
print(sanitized_page)
There is also the async_generator library which supports yield from
constructs.