tg-me.com/pyproglib/6654
Last Update:
Async-инициализация в Python: какие есть подходы
В Python нет нативной поддержки асинхронного __init__
, поэтому приходится искать обходные пути, если объект требует асинхронной инициализации (например, получения ресурса через await get_resource()
).
class Klass:
def __init__(self, resource):
self.resource = resource
@classmethod
async def initialize(cls):
resource = await get_resource()
return cls(resource)
— Лаконично
— Хорошо отделяет sync и async логику
— Удобно для тестов
— Нет устоявшейся конвенции
— Может быть неочевидно для команды
class Klass:
async def __aenter__(self):
self.resource = await get_resource()
return self
async def __aexit__(self, exc_type, exc, tb):
pass
— Устоявшийся паттерн (
async with
)— Удобно добавлять логику очистки в будущем
— Нужно писать
async with
при каждом использовании— Не всегда удобно, если объект нужен за пределами контекста
class Klass:
def __init__(self):
self.ready_event = asyncio.Event()
asyncio.create_task(self._load())
async def _load(self):
self.resource = await get_resource()
self.ready_event.set()
async def use(self):
await self.ready_event.wait()
await do_something_with(self.resource)
— Можно запускать загрузку параллельно с другими задачами
— Подходит для высоконагруженных систем
— Сложнее в отладке
— Нужно явно проверять
await ready_event.wait()
— легко забыть— Нет встроенного механизма очистки
Просто выносим всю асинхронную инициализацию за пределы класса.
— Чистый и легко тестируемый код
— Гибко масштабируется
— Логика разнесена по разным местам
— Использование может стать чуть более многословным
Гибридный подход: конструктор sync, а использование — с явной асинхронной инициализацией.
klass = Klass()
await klass.ready()
class Klass:
def __new__(cls, *args, **kwargs):
raise RuntimeError("Используйте `await Klass.create()`")
@classmethod
async def create(cls):
self = super().__new__(cls)
self.resource = await get_resource()
return self
initialize()
— простая async-инициализация без очистки__aenter__
/__aexit__
— нужна очистка или сложный жизненный циклcreate_task()
+ Event
— нужно запускать инициализацию в фоне.ready()
— чистое разделение этапов__new__
+ async — строгий контроль над созданиемБиблиотека питониста #буст