Большинство магических методы не предназначены для работы с 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__
, хотя это может быть не изящно