Как мне вызвать асинхронный код из метода __iter__? ⇐ Python

Программы на Python
Anonymous
Как мне вызвать асинхронный код из метода __iter__?

Сообщение Anonymous »

Новинка в асинхронности.
У меня был класс PGServer, который можно было перебирать, чтобы получить список имен баз данных:

Код: Выделить всё

class PGServer:
# ...connection code omitted...
def _databases( self ):
curr = self.connection().cursor()
curr.execute( "SELECT datname FROM pg_database ORDER BY datname" )
return [ row[ 0 ] for row in curr.fetchall() ]

def __iter__( self ):
return iter( self._databases() )

dbs = PGServer( ...connection params... )
for db in dbs:
print( db )
С psycopg все работало нормально. Затем я переключился на asyncpg:

Код: Выделить всё

class PGServer:
# ...connection code omitted...
async def _databases( self ):
conn = await self.connection()
rows = await conn.fetch( "SELECT datname FROM pg_database ORDER BY datname" )
return [ row[ 0 ] for row in rows ]

dbs = PGServer( ...connection params... )
for db in await dbs._databases():
print( db )
Это работает, когда я напрямую вызываю _databases(), но как мне заставить __iter__ снова работать? Я не могу сделать его асинхронным, потому что это нарушает протокол. Вместо этого я попробовал реализовать __aiter__, но не смог понять, как заставить это работать.
Некоторые реализации, которые я пробовал:

Код: Выделить всё

async def __aiter__( self ):
#return self._databases()
#return await self._databases()
#return aiter( self._databases() )
return aiter( await self._databases() )
Все они выдали следующую ошибку:

Код: Выделить всё

TypeError: 'async for' received an object from __aiter__ that does not implement __anext__: coroutine
ОБНОВЛЕНИЕ
Я только что создал реализацию, которая, похоже, работает:

Код: Выделить всё

async def __aiter__( self ):
for db in await self._databases():
yield name
Однако я не знаю, является ли это оптимальным или идиоматическим.
ОБНОВЛЕНИЕ 2
Если только кто-то может придумать что-то получше, я просто откажусь от __iter__ и скажу, что db in dbs:, и вместо этого просто буду более явным:

Код: Выделить всё

for db in await dbs.databases():
...
(Я убрал подчеркивание, потому что в этом новом контексте Databases() теперь является общедоступным API.)


Подробнее здесь: https://stackoverflow.com/questions/790 ... ter-method

Вернуться в «Python»