Це частина циклу статей про синтаксичний цукор у Python, у якій ми розглянемо роботу async
та await
.
Розбираємося з async
Найперше гляньмо під капот async
. Виявляється, що розібратися з async def
досить просто завдяки декоратору types.coroutine
, від якого і походить async def.
Цей декоратор встановлює прапорець на об'єкті коду для генератора, щоб відрізнити його від будь-якого іншого простого генератора. Іншими словами, функції async
і є генераторами.
Розбираємося з await
Очевидно, що вираз awaitє похідним від
yield from, але з двома основними особливостями: перевіркою того, чи
може об'єкт застосовуватися з функцією await, і підтримкою цих об'єктів, які визначає __await__()
.
Стандартна бібліотека надає функцію inspect.isawaitable()
, щоб визначити, чи може об'єкт застосовуватися з функцією await. З першою особливістю розібралися.
Інша особливість — це те, як викликати співпрограму, або корутину, через yield from
. Об'єкти, що працюють з функцією await, можуть або визначатися як __await __ (),
який повертає ітероване, або бути генератором, позначеним як співпрограма. Відтак ми повинні підтримувати обидва ці сценарії. Як і у попередніх прикладах зі спеціальними методами, нам потрібно отримати метод __await__()
безпосередньо з типу, а потім викликати його разом з об'єктом. Інакше обидва типи об'єктів, що можуть застосовуватися з функцією await, стають об'єктами, які можна передати до yield from
.
def _await(coroutine):
"""Simulate `await coroutine`."""
if not inspect.isawaitable(coroutine):
msg = f"object {builtins.type(coroutine)} can't be used in 'await' expression"
raise TypeError(msg)
coroutine_type = builtins.type(coroutine)
try:
__await__ = _mro_getattr(coroutine_type, "__await__")
except AttributeError:
awaitable = coroutine
else:
awaitable = __await__(coroutine)
yield from awaitable
Код для імітації await
Завдяки тому, як у Python побудовано async
та await
, ми вже мали всі потрібні блоки, щоб розібратися з синтаксисом і, по суті, перейти на попередні версії Python!
Ще немає коментарів