Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is python3.6 new change 'async for' not compatible with enumerate

I am trying to move my apps from python2.7 to python3.6,for the asyncio and relates libs,but I find some functions are not working as I excepted. I use motor to query from mongodb asyncly,like:

async def do_query():
    song_already_processed = set()
    song_table = db.song_table
    async for index, item in enumerate(song_table.find({'lang': 'English'},
                              {'id': 1, '_id': 0, 'title': 1, 'artist.name': 1})):
        if index > 100:
            break
        if item['id'] in song_already_processed:
            continue
        song_already_processed.add(item['id'])

    print(len(song_already_processed))

but it raised the error:

TypeError: 'AsyncIOMotorCursor' object is not iterable

I think the async iterator protocol is diffirent from normal interator protocol,so the enumerate didn't work well.Is there is an async enumerate I can use?

By the way, I know a lot of ways to just get 100 doc and stop the iterate, I just want to know how to use 'async for' properly

like image 991
Tarjintor Avatar asked Jan 03 '18 03:01

Tarjintor


People also ask

Is async a keyword in the latest python3?

The async/await keywords were standardized in Python 3.7. They simplify asynchronous programming in Python. The async keyword is used to create a Python coroutine. The await keyword suspends execution of a coroutine until it completes and returns the result data.

Is Python async by default?

Python, like many other languages, suffers from not being asynchronous by default. Fortunately, rapid changes in the IT world allow us to write asynchronous code even using languages that weren't originally meant to do so.

Does Python support asynchronous?

Async IO is a concurrent programming design that has received dedicated support in Python, evolving rapidly from Python 3.4 through 3.7, and probably beyond. You may be thinking with dread, “Concurrency, parallelism, threading, multiprocessing.

Is Python a sync or async?

Async functions need to run on an event loop, and while they can call synchronous functions, it's dangerous. Sync functions just run on bare Python, and to have them call to asynchronous functions you need to either find or make an event loop to run the code in.


1 Answers

The asyncstdlib library (disclaimer: I maintain this package) provides async variants of standard library helpers. In specific, asyncstdlib.enumerate works like enumerate but takes and produces an async iterable.

import asyncstdlib as a

async for index, item in a.enumerate(song_table.find(...)):
    if index > 100:
        break
    ...

Note that it is generally not a good idea to break out of an async iteration -- the iterator may not cleanup at the end of iteration (see PEP 533 for details).

Since you are using index just to get the first 100 items, you can also use asyncstdlib.islice to safely limit the iteration directly:

import asyncstdlib as a

async for item in a.islice(song_table.find(...), 100):
    ...

Python3.6 added asynchronous generators, which allows to easily implement async enumeration:

async def aenumerate(asequence, start=0):
    """Asynchronously enumerate an async iterator from a given start value"""
    n = start
    async for elem in asequence:
        yield n, elem
        n += 1

For older versions of Python, one must reify the async generator by hand:

class AsyncEnumerate:
    """Asynchronously enumerate an async iterator from a given start value"""
    def __init__(self, asequence, start=0):
        self._asequence = asequence
        self._value = start

    async def __anext__(self):
        elem = await self._asequence.__anext__()
        value, self._value = self._value, self._value + 1
        return value, elem

    def __aiter__(self):
        return self
like image 80
MisterMiyagi Avatar answered Oct 03 '22 00:10

MisterMiyagi