Асинхронные менеджеры контекста и итераторы
Реализуйте протоколы async with и async for.
«Асинхронные менеджеры контекста и итераторы» — бесплатный урок Python Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Python Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Python Academy содержит 4 уроков всего.
Инструкция async with
Используйте async with для менеджеров контекста, настройка и освобождение ресурсов которыми требуют ожидания операций ввода-вывода. Управляемый объект должен реализовывать __aenter__ и __aexit__.
import asyncio
class AsyncFile:
async def __aenter__(self):
print("open")
return self
async def __aexit__(self, *args):
print("close")
async def main():
async with AsyncFile() as f:
print("using")
asyncio.run(main())__aenter__ и __aexit__
Оба метода являются сопрограммами. При входе ожидается __aenter__, а при выходе ожидается __aexit__, даже если произошло исключение.
import asyncio
class DBSession:
async def __aenter__(self):
self.conn = await async_connect()
return self.conn
async def __aexit__(self, exc_type, exc_val, exc_tb):
if exc_type:
await self.conn.rollback()
else:
await self.conn.commit()
await self.conn.close()
return False@asynccontextmanager
contextlib.asynccontextmanager позволяет записывать асинхронные менеджеры контекста в виде асинхронных функций-генераторов.
from contextlib import asynccontextmanager
import asyncio
@asynccontextmanager
async def managed_resource():
print("acquire")
try:
yield {"status": "ready"}
finally:
print("release")
async def main():
async with managed_resource() as r:
print(r["status"])
asyncio.run(main())Инструкция async for
async for перебирает асинхронный итерируемый объект — объект, реализующий __aiter__ и __anext__. Каждая итерация может включать операцию ввода-вывода.
import asyncio
class AsyncCounter:
def __init__(self, n): self.n, self.i = n, 0
def __aiter__(self): return self
async def __anext__(self):
if self.i >= self.n: raise StopAsyncIteration
await asyncio.sleep(0)
self.i += 1
return self.i
async def main():
async for val in AsyncCounter(3):
print(val)
asyncio.run(main())Асинхронные генераторы
Функция async def, содержащая yield, является асинхронным генератором. Используйте async for, чтобы получать из него значения.
import asyncio
async def ticker(n):
for i in range(n):
await asyncio.sleep(1)
yield i
async def main():
async for val in ticker(3):
print(val) # 0, 1, 2 with 1-s pauses
asyncio.run(main())aiofiles для асинхронного ввода-вывода файлов
Библиотека aiofiles оборачивает операции с файлами в асинхронные менеджеры контекста и асинхронные итераторы.
# pip install aiofiles
import aiofiles, asyncio
async def main():
async with aiofiles.open("data.txt", "r") as f:
async for line in f:
print(line.strip())Сеанс клиента aiohttp
aiohttp.ClientSession — это асинхронный менеджер контекста для выполнения параллельных HTTP-запросов.
# pip install aiohttp
import aiohttp, asyncio
async def fetch(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
return await resp.json()
asyncio.run(fetch("https://api.example.com/data"))Несколько асинхронных менеджеров контекста
Размещайте несколько предложений async with в одной строке (форма со скобками, доступная в Python 3.10 и более поздних версиях).
import asyncio
async def main():
async with (
open_db() as db,
open_cache() as cache,
):
data = await db.fetch("SELECT 1")
await cache.set("key", data)AsyncExitStack
contextlib.AsyncExitStack управляет динамическим набором асинхронных менеджеров контекста.
from contextlib import AsyncExitStack
import asyncio
async def main():
async with AsyncExitStack() as stack:
conn1 = await stack.enter_async_context(connect("db1"))
conn2 = await stack.enter_async_context(connect("db2"))
await process(conn1, conn2)Тестирование асинхронного кода с pytest-asyncio
pytest-asyncio позволяет писать асинхронные функции тестов с маркером @pytest.mark.asyncio.
# pip install pytest-asyncio
import pytest, asyncio
async def fetch(): return 42
@pytest.mark.asyncio
async def test_fetch():
result = await fetch()
assert result == 42Итоги протокола асинхронных итераторов
Объект является асинхронным итерируемым объектом, если у него есть __aiter__. Он является асинхронным итератором, если у него также есть __anext__. Асинхронные генераторы автоматически реализуют оба метода.
import asyncio
async def gen():
yield 1
yield 2
async def main():
g = gen()
print(await g.__anext__()) # 1
print(await g.__anext__()) # 2Быстрая проверка
Какие специальные методы должен реализовать объект, чтобы его можно было использовать с async with?
Итоги
Используйте async with для ресурсов, которым требуется асинхронная настройка и очистка. Используйте async for для итерируемых объектов, которые асинхронно создают значения. Асинхронные генераторы упрощают создание асинхронных итераторов. Такие библиотеки, как aiofiles и aiohttp, предоставляют асинхронные операции с файлами и HTTP.
Часто задаваемые вопросы
Урок «Асинхронные менеджеры контекста и итераторы» бесплатный?
Да — полный текст урока «Асинхронные менеджеры контекста и итераторы» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Python Academy, подпишись на CoddyKit PRO. Курс Python Academy содержит 4 уроков всего.
Чему я научусь в уроке «Асинхронные менеджеры контекста и итераторы»?
Реализуйте протоколы async with и async for. Ты практикуешь Python Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Python Academy?
Предыдущий опыт не требуется. Python Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Асинхронные менеджеры контекста и итераторы»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Python Academy?
Да. Каждый урок Python Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Корутины и цикл событий
- await, задачи и объединение результатов
- Асинхронные менеджеры контекста и итераторы
- Шаблоны асинхронного ввода-вывода в продуктивной среде