Большинство магических методы не предназначены для работы с async def/ await- в общем, вы должны использовать только awaitвнутри выделенные асинхронные методы магии - __aiter__, __anext__, __aenter__, и __aexit__. Использование его внутри других магических методов либо вообще не сработает, как в случае с__init__ (если вы не используете некоторые трюки, описанные в других ответах здесь), либо заставит вас всегда использовать все, что запускает вызов магического метода в асинхронном контексте.
Существующие asyncioбиблиотеки, как правило, справляются с этим одним из двух способов: во-первых, я видел, как используется фабричный шаблон ( asyncio-redisнапример):
import asyncio
dsn = "..."
class Foo(object):
@classmethod
async def create(cls, settings):
self = Foo()
self.settings = settings
self.pool = await create_pool(dsn)
return self
async def main(settings):
settings = "..."
foo = await Foo.create(settings)
Другие библиотеки используют функцию сопрограммы верхнего уровня, которая создает объект, а не фабричный метод:
import asyncio
dsn = "..."
async def create_foo(settings):
foo = Foo(settings)
await foo._init()
return foo
class Foo(object):
def __init__(self, settings):
self.settings = settings
async def _init(self):
self.pool = await create_pool(dsn)
async def main():
settings = "..."
foo = await create_foo(settings)
create_poolФункция от aiopgкоторый вы хотите звонить в __init__самом деле использует именно этот шаблон.
Это, по крайней мере, решает __init__проблему. Я не видел переменных класса, которые делают асинхронные вызовы в естественных условиях, которые я могу припомнить, поэтому я не знаю, возникли ли какие-либо устойчивые шаблоны.
__new__, хотя это может быть не изящно