Учим_Питон_#5 — Практика: асинхронные функции
2026-02-26 14:58 Diff

Внимание! Данный материал может содержать ошибки, и является лишь попыткой закрепить изученный материал через изложение. Комментарии с правками приветствуются.

Используем:

  • Python 3.9
  • Asyncio
  • Aiohttp
  • Postgresql
  • Docker
  • Sqlalchemy

Задача: написать асинхронный код, который скачивает данные с сайта и загружает их в БД.

Создаем 5 файлов:

  • main.py — точка входа для запуска программы
  • jsonplaceholder.py — модуль, скачивающий данные с сайта
  • models.py — ф-и для БД
  • docker-compose.yaml — информация для докера
  • postgres.env — логин, пароль, название БД

docker-compose.yaml:

postgres.env

jsonplaceholder.py

  • aiohttp — это «async HTTP client/server for asyncio and Python».
  • asyncio — это «a library to write concurrent code using the async/await syntax».
  • async — создает корутину
  • await — позволяет переключить контекст, переходя к другой ф-и, если текущая занята.
  • async with — асинхронный менеджер контекста, который автоматически закроется после выполнения задачи (см. Менеджер контекста или with as)

Корутина — cooperative routine, код, который может выполняться одновременно с другим кодом.

Что мы здесь делаем:

  • Импортируем библиотеки Пишем константы (по соглашению разработчиков, константы — это переменные, записанные с большой буквы, и которые НЕ следует менять!)

  • Создаем асинхронную ф-и(корутину) fetch_json — дословно: «получить json».

  • Внутри ф-и вызываем асинхронный менеджер, в нем открываем сессию через aiohttp, и следующим шагом посылаем запрос GET по урлу session.get(url). Результат кладем в переменную response и возвращаем его, преобразовав в json (return await response.json()) — код с return читается справа налево. Вначале await переменной, затем return того, что получилось)

Важно: данные, приходящие с сервера, не нужно мутировать! Почему? Потому что другие разработчики знают, как работает json() и ожидают json, а не мутанта:) Не усложняйте жизнь другим и себе, например, спустя месяц.

Итак, результат работы модуля jsonplaceholder.py — возврат данных в виде json

Импортируем модуль даты и времени

from datetime import datetime

Импортируем логгер (типа дебаггера)

Импортируем ORM для работы с БД

Импортируем асинхронные методы sqlalchemy для работы с БД

from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession

Импортируем метод работы с бд, фабрику сессий и связи

Создаем движок

Создаем метод описания БД (Создаем базовый класс для декларативных определений классов.)

Создаем сессию (Фабрика sessionmaker генерирует новые объекты Session при вызове)

Session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)

Запускаем докер, вызвав команду в консоли используя create_subprocess_shell(cmd)

cmd = 'docker compose up -d' async def create_pg_docker(cmd): result = await asyncio.create_subprocess_shell(cmd) await result.communicate() logger.info('____pg docker rdy')

Делаем DROP TABLE, CREATE TABLE в БД

Cоздаем ф-ю, которая скачивает с сайта юзеров и сохраняет их в БД

Cоздаем ф-ю, которая скачивает с сайта посты и сохраняет их в БД

Создаем модель таблицы User и Post

Результат работы модуля models.py:

  1. Подключаемся к БД в докере
  2. Дропаем и создаем заново таблицы (чтобы небыло конфликта с существующими записями)
  3. Сохраняем данные юзеров и постов в БД

main.py:

Что здесь делаем:

Создаем асинхронный main() и запускаем его в синхронном main(). Внутри async_main() последовательно запускаем асинхронные ф-и:

  1. Запуск БД в докере
  2. Дроп и создание пустых таблиц
  3. Получение данных юзеров и постов с сайта
  4. Сохранение юзеров в бд
  5. Сохранение постов в бд
  6. Закрытие подключения к бд (происходит неявно, автоматически при завершении работы менеджера контекста)
  • asyncio.gather — метод, который вернет то, что в него было положено, в том же порядке. (deprecated in python 3.10!!!)
  • asyncio.run - метод, создающий event loop для асинхронных ф-ий.

Результат работы main.py: В БД, в таблице User появляется 10 пользователей, в таблице Post — 100 записей, связанных отношением many to one к юзерам, написавших их.

P.S. Если будете копировать код - используйте IDE для его запуска т.к. где-то может стоять 4 пробела, а где-то табуляция. Но лучше не копировать, а руками перепечатать, так лучше запомнится и поймется.