0Pricing
Python Academy · Урок

Асинхронные менеджеры контекста и итераторы

Реализуйте протоколы 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 — локальная установка не требуется.

Все уроки этого курса

  1. Корутины и цикл событий
  2. await, задачи и объединение результатов
  3. Асинхронные менеджеры контекста и итераторы
  4. Шаблоны асинхронного ввода-вывода в продуктивной среде
← Назад к Python Academy