[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-80619":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":13,"stars7d":12,"stars30d":16,"stars90d":15,"forks30d":15,"starsTrendScore":17,"compositeScore":18,"rankGlobal":9,"rankLanguage":9,"license":9,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":21,"hasPages":19,"topics":22,"createdAt":9,"pushedAt":9,"updatedAt":23,"readmeContent":24,"aiSummary":25,"trendingCount":15,"starSnapshotCount":15,"syncStatus":14,"lastSyncTime":26,"discoverSource":27},80619,"pythonroamap2026","justxor\u002Fpythonroamap2026","justxor","Python полная дорожная карта для изучения языка в 2026 году",null,"Python",101,14,1,2,0,43,9,53.83,false,"main",true,[],"2026-06-12 04:01:29","# 🐍 Python Roadmap 2026 (RU) — расширенная версия\n\n> Полный и **актуальный** маршрут изучения Python в 2026 году: от `Hello, World` до Senior \u002F архитектора.\n> С практикой, схемами, примерами кода и **только бесплатными** ресурсами.\n\n> Python 3.13+ • free-threaded mode (PEP 703) • JIT (PEP 744) • uv\u002Fruff • async-first • type-driven • AI-инфраструктура\n\n![Python](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FPython-3.13%2B-blue)\n![Status](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fstatus-actual%202026-brightgreen)\n![Free](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fresources-free-orange)\n![Telegram](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FTelegram-%40pythonl-26A5E4?logo=telegram)\n![License](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-MIT-green)\n\n> 🔗 **Навигация:** [🗺 Карта обучения](course\u002FMAP.md) · [📖 Глоссарий](course\u002Fglossary.md) · [🎯 Промпты для LLM](course\u002Fprompts\u002FREADME.md) · [⚡ Стартер-скрапер](templates\u002Fscraper-starter\u002FREADME.md) · [📡 t.me\u002Fpythonl](https:\u002F\u002Ft.me\u002Fpythonl)\n\n🎓 **Практический курс по этому роадмапу:** [course\u002FREADME.md](course\u002FREADME.md) — уроки, примеры кода, упражнения и решения по каждому этапу. Отдельные этапы:\n> - [🤖 Вайбкодинг (AI-assisted dev)](course\u002Fstage-14-vibecoding.md) — Claude Code, Cursor, Copilot, локальные модели.\n> - [🕸 Парсинг и веб-скрапинг 2026](course\u002Fstage-15-parsing.md) — httpx, selectolax, Playwright, Scrapy, crawl4ai, антибот, этика.\n> - [🤖 Machine Learning на Python (2026)](course\u002Fstage-16-ml.md) — sklearn, LightGBM\u002FCatBoost, PyTorch + Lightning, HuggingFace, Optuna, MLflow, BentoML, drift-мониторинг.\n> - [🧠 LLM-приложения (2026)](course\u002Fstage-17-llm-apps.md) — RAG, агенты, LangGraph, MCP, vLLM, eval, guardrails.\n> - [🌊 **Курс по асинхронности 2026**](course\u002Fasync-course.md) — asyncio, TaskGroup, anyio, uvloop, free-threaded Python (PEP 703), production-чеклист.\n> - [🐳 **Курс по контейнерам 2026**](course\u002Fcontainers-course.md) — Docker, BuildKit, multi-stage, distroless, chainguard, Kubernetes, Helm, supply-chain security (trivy\u002Fcosign\u002FSBOM).\n\n📣 **Главные Telegram-источники этого роадмапа:**\n> - 🐍 **[t.me\u002Fpythonl](https:\u002F\u002Ft.me\u002Fpythonl)** — главный канал по Python: новости, библиотеки, разборы, вакансии.\n> - 🤖 **[t.me\u002Fai_machinelearning_big_data](https:\u002F\u002Ft.me\u002Fai_machinelearning_big_data)** — практика и примеры кода по AI \u002F ML \u002F Big Data на Python: модели, ноутбуки, бенчмарки, статьи с разбором.\n> - 📚 **[Отборная папка ресурсов 🎁](https:\u002F\u002Ft.me\u002Faddlist\u002F8vDUwYRGujRmZjFi)** — кураторская подборка лучших Telegram-каналов по Python, ML, DS и инфраструктуре. Подписался один раз — закрыл вопрос «где брать актуальное».\n\n---\n\n## 🗺️ Общая карта пути\n\n```\n                  ┌──────────────────────────────────────────────┐\n                  │              🐍 PYTHON ROADMAP 2026          │\n                  └──────────────────────────────────────────────┘\n                                       │\n   ┌───────────────────────┬───────────┴───────────┬───────────────────────┐\n   ▼                       ▼                       ▼                       ▼\n┌──────────┐         ┌──────────┐            ┌──────────┐           ┌──────────┐\n│ Месяц 1  │         │ Месяц 2-3│            │ Месяц 4-6│           │ Месяц 7-9│\n│ Этапы 0-2│  ───▶   │ Этапы 3-5│   ───▶     │Этапы 6-9 │  ───▶     │Этапы10-13│\n│ОСНОВЫ ЯЗ.│         │ STDLIB + │            │ ASYNC +  │           │ARCH + ML │\n│          │         │ OOП + TYP│            │  WEB     │           │  + DEVOPS│\n└──────────┘         └──────────┘            └──────────┘           └──────────┘\n   Junior              Junior+                  Middle                 Middle+\n                                                                       Senior\n```\n\n### Логика следования этапов\n\n```\n[0] Окружение ──▶ [1] Основы ──▶ [2] Идиомы ──▶ [3] ООП ──▶ [4] Типы ──▶ [5] Stdlib\n                                                                            │\n        ┌───────────────────────────────────────────────────────────────────┘\n        ▼\n[6] Async ──▶ [7] Тесты ──▶ [8] CPython внутри ──▶ [9] Web ──▶ [10] БД ──▶ [11] ML\u002FAI\n                                                                                  │\n                              ┌───────────────────────────────────────────────────┘\n                              ▼\n                       [12] DevOps ──▶ [13] Архитектура \u002F Senior\n```\n\n---\n\n## 📌 Как пользоваться роадмапом\n\n1. **По этапам**, не перепрыгивая. Каждый раздел опирается на предыдущий.\n2. На каждом этапе: **теория → код руками → мини-проект → разбор чужого кода**.\n3. Минимум **70% времени — код руками**, без копипасты.\n4. Веди репозиторий-дневник `learning-python\u002Fweek-XX\u002F` — коммить туда решения задач.\n5. Раз в неделю — code review (свой старый код или открытый PR на GitHub).\n6. Каждый этап заканчивается **чеклистом** — пока не отметишь всё, не идёшь дальше.\n7. Подпишись на [t.me\u002Fpythonl](https:\u002F\u002Ft.me\u002Fpythonl) и читай раз в день — это держит «в курсе».\n\n⏱ Ориентировочный темп: **6–9 месяцев** при 2–3 часах в день → уверенный Junior+\u002FMiddle.\n\n---\n\n## 🧭 Содержание\n\n- [Этап 0. Окружение 2026](#этап-0-окружение-2026)\n- [Этап 1. Основы языка](#этап-1-основы-языка)\n- [Этап 2. Идиоматичный Python](#этап-2-идиоматичный-python)\n- [Этап 3. ООП и проектирование](#этап-3-ооп-и-проектирование)\n- [Этап 4. Типизация](#этап-4-типизация)\n- [Этап 5. Стандартная библиотека](#этап-5-стандартная-библиотека)\n- [Этап 6. Асинхронность и конкурентность](#этап-6-асинхронность-и-конкурентность)\n- [Этап 7. Тестирование и качество кода](#этап-7-тестирование-и-качество-кода)\n- [Этап 8. Внутренности CPython](#этап-8-внутренности-cpython)\n- [Этап 9. Web-разработка](#этап-9-web-разработка)\n- [Этап 10. Базы данных и ORM](#этап-10-базы-данных-и-orm)\n- [Этап 11. Data \u002F ML \u002F AI](#этап-11-data--ml--ai)\n- [Этап 12. DevOps и продакшн](#этап-12-devops-и-продакшн)\n- [Этап 13. Архитектура и Senior](#этап-13-архитектура-и-senior)\n- [📚 Бесплатные ресурсы](#-бесплатные-ресурсы-общая-подборка)\n- [🤖 Вайбкодинг (AI-assisted dev)](#-вайбкодинг--разработка-с-ai-в-2026)\n- [💬 Telegram-каналы](#-telegram-каналы-2026)\n- [🧠 Платформы для практики](#-платформы-для-практики)\n- [✅ Финальный чеклист Middle+](#-финальный-чеклист-middle)\n\n---\n\n## Этап 0. Окружение 2026\n\n> 🎯 **Цель:** настроить современный стек один раз — и забыть о боли с зависимостями навсегда.\n> ⏱ **Время:** 1–2 вечера.\n\n### Карта стека\n\n```\n┌──────────────────────────────────────────────────────────────┐\n│                      ВЕРСИЯ PYTHON                           │\n│   python 3.13+ (CPython)   ▒    python 3.13t (free-threaded) │\n└──────────────────────────────────────────────────────────────┘\n              │\n              ▼\n┌──────────────────────────────────────────────────────────────┐\n│                  ПАКЕТНЫЙ МЕНЕДЖЕР                           │\n│        uv  ◀── заменяет pip + venv + poetry + pyenv          │\n└──────────────────────────────────────────────────────────────┘\n              │\n              ▼\n┌──────────────────────────────────────────────────────────────┐\n│       КАЧЕСТВО КОДА            │        ТЕСТЫ                │\n│   ruff   (lint + format)       │   pytest                    │\n│   pyright (типы)               │   hypothesis                │\n│   pre-commit (хуки)            │   coverage                  │\n└──────────────────────────────────────────────────────────────┘\n              │\n              ▼\n┌──────────────────────────────────────────────────────────────┐\n│                       IDE                                    │\n│  VS Code + Pylance + Ruff   │  PyCharm 2026   │  Zed + LSP   │\n└──────────────────────────────────────────────────────────────┘\n```\n\n### Стек подробно\n\n| Инструмент | Заменяет | Зачем |\n|---|---|---|\n| **Python 3.13+** | — | основной интерпретатор, JIT и nogil доступны |\n| **uv** (Astral) | pip, pipx, venv, poetry, pyenv | в 10–100× быстрее, единый CLI |\n| **ruff** | black, isort, flake8, pylint | один линтер + форматтер, на Rust |\n| **pyright** или **mypy --strict** | — | статический контроль типов |\n| **pytest** + **hypothesis** | unittest | де-факто стандарт |\n| **pre-commit** | — | хуки качества до коммита |\n| **direnv** + `.envrc` | venv activate | автоактивация окружения |\n| **Docker \u002F OrbStack** | — | контейнеры |\n\n### Практика (выполнить целиком)\n\n```bash\n# 1. Установка uv (macOS\u002FLinux)\ncurl -LsSf https:\u002F\u002Fastral.sh\u002Fuv\u002Finstall.sh | sh\n\n# 2. Установка нужной версии Python\nuv python install 3.13\n\n# 3. Новый проект\nuv init my-first-project && cd my-first-project\n\n# 4. Зависимости разработки\nuv add --dev ruff pyright pytest hypothesis pre-commit\n\n# 5. Создаём базовый код и тест\nmkdir src tests\necho 'def add(a: int, b: int) -> int: return a + b' > src\u002Fcalc.py\necho 'from src.calc import add\ndef test_add(): assert add(2, 3) == 5' > tests\u002Ftest_calc.py\n\n# 6. Проверяем линтер, типы и тесты\nuv run ruff check .\nuv run pyright\nuv run pytest -q\n\n# 7. Подключаем pre-commit\necho '\nrepos:\n  - repo: https:\u002F\u002Fgithub.com\u002Fastral-sh\u002Fruff-pre-commit\n    rev: v0.8.0\n    hooks:\n      - id: ruff\n      - id: ruff-format\n' > .pre-commit-config.yaml\nuv run pre-commit install\n```\n\n### Эталонный `pyproject.toml`\n\n```toml\n[project]\nname = \"my-first-project\"\nversion = \"0.1.0\"\nrequires-python = \">=3.13\"\ndependencies = []\n\n[dependency-groups]\ndev = [\"ruff\", \"pyright\", \"pytest\", \"hypothesis\", \"pre-commit\"]\n\n[tool.ruff]\nline-length = 100\ntarget-version = \"py313\"\n\n[tool.ruff.lint]\nselect = [\"E\", \"F\", \"I\", \"B\", \"UP\", \"SIM\", \"RUF\", \"ANN\", \"TID\", \"C4\", \"PT\"]\nignore = [\"ANN101\", \"ANN102\"]\n\n[tool.ruff.format]\nquote-style = \"double\"\n\n[tool.pyright]\ntypeCheckingMode = \"strict\"\npythonVersion = \"3.13\"\n\n[tool.pytest.ini_options]\naddopts = \"-ra -q\"\ntestpaths = [\"tests\"]\n```\n\n### 🛠 Мини-задачи\n\n1. Поднять проект по шагам выше.\n2. Сломать тест намеренно — посмотреть, как падает pre-commit.\n3. Добавить хук pyright в pre-commit вручную.\n4. Завести GitHub-репозиторий `learning-python` для всех будущих проектов.\n\n### 📚 Бесплатные ресурсы этапа 0\n\n- 📘 [uv docs](https:\u002F\u002Fdocs.astral.sh\u002Fuv\u002F) — официальная документация.\n- 📘 [ruff docs](https:\u002F\u002Fdocs.astral.sh\u002Fruff\u002Frules\u002F) — все правила линтера.\n- 📘 [pyright getting started](https:\u002F\u002Fmicrosoft.github.io\u002Fpyright\u002F#\u002Fgetting-started).\n- 🎥 [ArjanCodes — Modern Python tooling (uv\u002Fruff)](https:\u002F\u002Fwww.youtube.com\u002F@ArjanCodes).\n- 📝 [Hynek Schlawack — Production-ready Python](https:\u002F\u002Fhynek.me\u002Farticles\u002F) — серия о современном стеке.\n- 📘 [Awesome uv](https:\u002F\u002Fgithub.com\u002Ftox-dev\u002Fawesome-uv).\n- 💬 [t.me\u002Fpythonl](https:\u002F\u002Ft.me\u002Fpythonl) — там часто разбирают новости uv\u002Fruff.\n\n### ✅ Чеклист этапа 0\n\n- [ ] uv, ruff, pyright, pytest установлены и работают\n- [ ] Создан репозиторий-дневник на GitHub\n- [ ] pre-commit запускается при `git commit`\n- [ ] Понимаю отличие `uv sync` от `pip install -r requirements.txt`\n- [ ] Знаю, чем `uv lock` отличается от `pip freeze`\n\n---\n\n## Этап 1. Основы языка\n\n> 🎯 **Цель:** уверенно реализовать любой алгоритм на чистом Python.\n> ⏱ **Время:** 3–4 недели.\n\n### Карта раздела\n\n```\n                    ┌─────────────── ОСНОВЫ ЯЗЫКА ──────────────┐\n                    │                                           │\n   ┌────────────┐ ┌─┴──────────┐ ┌──────────────┐ ┌─────────────┴──┐\n   │ Синтаксис  │ │  Типы      │ │  Управление  │ │   Функции      │\n   │ PEP 8      │ │  данных    │ │  потоком     │ │   замыкания    │\n   └────────────┘ └────────────┘ └──────────────┘ └────────────────┘\n                                                           │\n                          ┌────────────────┬───────────────┘\n                          ▼                ▼\n                  ┌─────────────┐ ┌─────────────────┐\n                  │ Исключения  │ │ Контекстные     │\n                  │ try\u002Fexcept  │ │ менеджеры (with)│\n                  └─────────────┘ └─────────────────┘\n```\n\n### Темы детально\n\n| Подтема | Что освоить | Минимум практики |\n|---|---|---|\n| **Базовый синтаксис** | отступы, переменные, операторы | 5 простых скриптов |\n| **Числа** | int, float, Decimal, Fraction, complex | калькулятор процентов и НДС |\n| **Строки** | методы, f-strings (`f\"{x=}\"`, `f\"{n:_>10.2f}\"`), join, split | парсер логов |\n| **bytes\u002Fbytearray** | encode\u002Fdecode, hex, base64 | парсер бинарного формата |\n| **Коллекции** | list, tuple, set, frozenset, dict | реализовать частотный словарь |\n| **`match\u002Fcase`** | structural pattern matching | парсер JSON-событий |\n| **Функции** | `*args`, `**kwargs`, `\u002F`, `*`, аннотации | 10 функций с разными сигнатурами |\n| **LEGB scope** | глобальные\u002Fлокальные\u002Fnonlocal | счётчик через замыкание |\n| **Исключения** | try\u002Fexcept\u002Felse\u002Ffinally, `raise ... from` | свой класс ошибок |\n| **`with`** | контекстные менеджеры, contextlib | тайм-замер блока кода |\n\n### Пример: structural pattern matching\n\n```python\ndef handle(event: dict) -> str:\n    match event:\n        case {\"type\": \"click\", \"x\": int(x), \"y\": int(y)}:\n            return f\"click at ({x},{y})\"\n        case {\"type\": \"key\", \"key\": str(k)} if k.isalpha():\n            return f\"letter {k.upper()}\"\n        case {\"type\": \"key\"}:\n            return \"non-letter key\"\n        case {\"type\": t, **rest}:\n            return f\"unknown type={t}, extra={rest}\"\n        case _:\n            return \"not an event\"\n\nprint(handle({\"type\": \"click\", \"x\": 10, \"y\": 20}))   # click at (10,20)\nprint(handle({\"type\": \"key\", \"key\": \"a\"}))           # letter A\n```\n\n### Пример: контекстный менеджер таймера\n\n```python\nfrom contextlib import contextmanager\nfrom time import perf_counter\n\n@contextmanager\ndef timer(label: str):\n    start = perf_counter()\n    try:\n        yield\n    finally:\n        print(f\"{label}: {perf_counter() - start:.3f}s\")\n\nwith timer(\"sum\"):\n    total = sum(range(10_000_000))\n```\n\n### Пример: свой класс исключений\n\n```python\nclass AppError(Exception): ...\nclass NotFoundError(AppError): ...\nclass ValidationError(AppError):\n    def __init__(self, field: str, reason: str):\n        super().__init__(f\"{field}: {reason}\")\n        self.field, self.reason = field, reason\n\ndef find(user_id: int):\n    if user_id \u003C 0:\n        raise ValidationError(\"user_id\", \"must be >= 0\")\n    raise NotFoundError(f\"user {user_id} not found\")\n\ntry:\n    find(-1)\nexcept AppError as e:\n    print(type(e).__name__, e)\n```\n\n### 🛠 Мини-проекты этапа 1\n\n1. **CLI-калькулятор** с поддержкой выражений и истории (`argparse` + `match`).\n2. **CSV → JSON** парсер без сторонних библиотек (только stdlib).\n3. **«Угадай число»** с сохранением статистики в файл.\n4. **Анализатор текста**: топ-10 слов, частота букв, среднее число слов в предложении.\n5. **Конвертер валют** на курсах из локального JSON.\n\n### 📚 Бесплатные ресурсы этапа 1\n\n- 📘 [Официальный туториал Python (RU)](https:\u002F\u002Fdocs.python.org\u002F3\u002Ftutorial\u002Findex.html).\n- 📘 [pythontutor.ru](https:\u002F\u002Fpythontutor.ru\u002F) — учебник + задачи на русском.\n- 📘 [Real Python — Python Basics](https:\u002F\u002Frealpython.com\u002Ftutorials\u002Fbasics\u002F).\n- 📘 [Automate the Boring Stuff (free online)](https:\u002F\u002Fautomatetheboringstuff.com\u002F).\n- 🎮 [CheckiO](https:\u002F\u002Fcheckio.org\u002F) — задачи в виде игры.\n- 🎮 [Exercism Python Track](https:\u002F\u002Fexercism.org\u002Ftracks\u002Fpython) — бесплатно, с менторами.\n- 🎥 [Corey Schafer — Python Tutorial (плейлист)](https:\u002F\u002Fwww.youtube.com\u002Fplaylist?list=PL-osiE80TeTt2d9bfVyTiXJA-UTHn6WwU).\n- 🎥 [selfedu — Python 3 (RU)](https:\u002F\u002Fwww.youtube.com\u002F@selfedu_rus).\n- 💬 [t.me\u002Fpythonl](https:\u002F\u002Ft.me\u002Fpythonl) — рубрики «задача дня».\n\n### ✅ Чеклист этапа 1\n\n- [ ] Решил 30+ задач на pythontutor.ru \u002F CheckiO \u002F Exercism\n- [ ] Реализовал минимум 2 мини-проекта из списка\n- [ ] Уверенно использую f-strings и `match\u002Fcase`\n- [ ] Различаю изменяемые и неизменяемые типы (list vs tuple, dict vs frozenset)\n- [ ] Написал свою иерархию исключений\n- [ ] Понимаю LEGB и применяю `nonlocal`\n\n---\n\n## Этап 2. Идиоматичный Python\n\n> 🎯 **Цель:** писать «по-питоновски». Меньше кода — больше выразительности.\n> ⏱ **Время:** 2–3 недели.\n\n### Карта раздела\n\n```\n   ┌──────────────────── ИДИОМАТИЧНЫЙ PYTHON ────────────────────┐\n   │                                                             │\n┌──┴───────────┐   ┌───────────────┐   ┌────────────────┐   ┌────┴────────┐\n│ Итераторы \u002F  │   │ Comprehensions│   │ itertools \u002F    │   │ Декораторы  │\n│ Генераторы   │   │ list\u002Fdict\u002Fgen │   │ functools      │   │ @wraps      │\n└──────────────┘   └───────────────┘   └────────────────┘   └─────────────┘\n        │                                       │\n        ▼                                       ▼\n   ┌────────────┐                       ┌────────────────┐\n   │ EAFP \u002F LBYL│                       │ dataclasses \u002F  │\n   │ walrus :=  │                       │ namedtuple     │\n   └────────────┘                       └────────────────┘\n```\n\n### Что должен уметь идиоматичный питонист\n\n| Антипаттерн ❌ | Идиома ✅ |\n|---|---|\n| `for i in range(len(xs)): xs[i]` | `for x in xs` \u002F `enumerate` |\n| `result = []; for x in xs: result.append(f(x))` | `[f(x) for x in xs]` |\n| `if x in dct: v = dct[x] else: v = default` | `v = dct.get(x, default)` |\n| `try: ... except KeyError: ...` для дефолта | `defaultdict` |\n| `fn(x); fn(x); fn(x)` | `@cache` |\n| мутабельный default `def f(x=[])` | `def f(x=None): x = x or []` |\n| ручной `time.time()` вокруг кода | контекстный менеджер `@contextmanager` |\n| `open(f); ... f.close()` | `with open(f) as ...` |\n\n### Пример: генератор vs список (память)\n\n```python\n# ❌ грузит всё в память\ndef squares_bad(n):\n    return [x*x for x in range(n)]\n\n# ✅ ленивая обработка\ndef squares_good(n):\n    yield from (x*x for x in range(n))\n\nfor sq in squares_good(10_000_000):\n    if sq > 100: break\n```\n\n### Пример: декоратор с аргументами\n\n```python\nfrom functools import wraps\nfrom time import sleep\n\ndef retry(times: int = 3, delay: float = 0.5):\n    def decorator(fn):\n        @wraps(fn)\n        def wrapper(*args, **kwargs):\n            for attempt in range(1, times + 1):\n                try:\n                    return fn(*args, **kwargs)\n                except Exception as e:\n                    if attempt == times:\n                        raise\n                    print(f\"retry {attempt}: {e}\")\n                    sleep(delay)\n        return wrapper\n    return decorator\n\n@retry(times=5, delay=0.2)\ndef flaky():\n    import random\n    if random.random() \u003C 0.7:\n        raise RuntimeError(\"oops\")\n    return \"done\"\n```\n\n### Пример: `itertools.batched` (3.12+) и `pairwise`\n\n```python\nfrom itertools import batched, pairwise\n\nfor chunk in batched(range(10), 3):\n    print(chunk)   # (0,1,2) (3,4,5) (6,7,8) (9,)\n\nfor a, b in pairwise([1, 3, 6, 10]):\n    print(b - a)   # 2 3 4\n```\n\n### Пример: `functools.singledispatch`\n\n```python\nfrom functools import singledispatch\n\n@singledispatch\ndef render(value) -> str:\n    return f\"\u003Cunknown {value!r}>\"\n\n@render.register\ndef _(value: int) -> str: return f\"int={value}\"\n\n@render.register\ndef _(value: list) -> str: return f\"list[{len(value)}]\"\n\nprint(render(10))          # int=10\nprint(render([1, 2, 3]))   # list[3]\n```\n\n### Пример: walrus `:=` к месту\n\n```python\nimport re\n\ntext = \"hello world 42\"\nif (m := re.search(r\"\\d+\", text)):\n    print(f\"число: {m.group()}\")\n```\n\n### 🛠 Практика\n\n- Реализовать декораторы: `@timed`, `@memoize`, `@deprecated`, `@retry`.\n- Переписать процедурный код предыдущего этапа в идиомы; замерить разницу через `ruff check --statistics`.\n- Заменить циклы накопления на comprehensions \u002F `sum` \u002F `any` \u002F `all` где уместно.\n- Написать генератор «скользящего окна» через itertools.\n\n### 📚 Бесплатные ресурсы этапа 2\n\n- 📘 [Python Cookbook (Beazley)](https:\u002F\u002Fgithub.com\u002Fdabeaz\u002Fpython-cookbook) — рецепты.\n- 📘 [itertools recipes (official)](https:\u002F\u002Fdocs.python.org\u002F3\u002Flibrary\u002Fitertools.html#itertools-recipes).\n- 📝 [Trey Hunner blog](https:\u002F\u002Ftreyhunner.com\u002Fblog\u002F) — лучшее об идиомах.\n- 🎥 [mCoding YouTube](https:\u002F\u002Fwww.youtube.com\u002F@mCoding).\n- 📘 [PEP 8](https:\u002F\u002Fpeps.python.org\u002Fpep-0008\u002F) и [PEP 20 — Zen of Python](https:\u002F\u002Fpeps.python.org\u002Fpep-0020\u002F).\n- 📝 [Real Python — Python Idioms](https:\u002F\u002Frealpython.com\u002Fpython-idioms\u002F).\n- 💬 [t.me\u002Fpythonl](https:\u002F\u002Ft.me\u002Fpythonl) — посты «как лучше написать».\n\n### ✅ Чеклист этапа 2\n\n- [ ] Написал минимум 4 рабочих декоратора\n- [ ] Свободно использую comprehensions\u002Fitertools\u002Ffunctools\n- [ ] Понимаю разницу `@cache` vs `@lru_cache(maxsize=N)`\n- [ ] Знаю, почему mutable default — антипаттерн\n- [ ] Применяю walrus только там, где он реально упрощает код\n- [ ] Различаю dataclass \u002F namedtuple \u002F TypedDict по применению\n\n---\n\n## Этап 3. ООП и проектирование\n\n> 🎯 **Цель:** проектировать гибкие, тестируемые системы. Думать «как поменять, не сломав».\n> ⏱ **Время:** 3 недели.\n\n### Карта раздела\n\n```\n                  ┌──────── ООП в Python ────────┐\n                  │                              │\n        ┌─────────┴────────┐         ┌───────────┴──────────┐\n        │   Базовые блоки  │         │  Принципы и паттерны │\n        │  class \u002F __init__│         │  SOLID \u002F DRY \u002F KISS  │\n        │  inheritance\u002FMRO │         │  GoF: Strategy,      │\n        │  dunder-методы   │         │  Factory, Adapter,   │\n        │  property        │         │  Observer, Repo...   │\n        └─────────┬────────┘         └───────────┬──────────┘\n                  ▼                              ▼\n        ┌───────────────────┐         ┌──────────────────────┐\n        │ Дескрипторы       │         │ Protocol (duck typed)│\n        │ Метаклассы (редко)│         │ vs ABC (формальный)  │\n        └───────────────────┘         └──────────────────────┘\n```\n\n### SOLID — в одну строку каждый\n\n- **S**ingle Responsibility — один класс = одна причина для изменения.\n- **O**pen\u002FClosed — открыт для расширения, закрыт для модификации.\n- **L**iskov Substitution — подкласс должен заменять родителя без сюрпризов.\n- **I**nterface Segregation — лучше много маленьких `Protocol`, чем один «толстый».\n- **D**ependency Inversion — зависим от абстракций (`Protocol`), а не от конкретных классов.\n\n### Топ магических методов (dunder)\n\n| Метод | Что даёт |\n|---|---|\n| `__repr__` \u002F `__str__` | вывод для отладки \u002F для пользователя |\n| `__eq__` + `__hash__` | сравнение и использование в set\u002Fdict |\n| `__iter__` \u002F `__next__` | объект-итератор |\n| `__enter__` \u002F `__exit__` | контекстный менеджер |\n| `__call__` | объект как функция |\n| `__len__`, `__getitem__` | поведение коллекции |\n| `__slots__` | экономия памяти |\n\n### Пример: Protocol вместо ABC\n\n```python\nfrom typing import Protocol, runtime_checkable\n\n@runtime_checkable\nclass SupportsArea(Protocol):\n    def area(self) -> float: ...\n\nclass Circle:\n    def __init__(self, r: float): self.r = r\n    def area(self) -> float: return 3.14159 * self.r ** 2\n\nclass Square:\n    def __init__(self, a: float): self.a = a\n    def area(self) -> float: return self.a ** 2\n\ndef total_area(shapes: list[SupportsArea]) -> float:\n    return sum(s.area() for s in shapes)\n\nprint(total_area([Circle(2), Square(3)]))   # 21.566...\n```\n\n### Пример: Strategy + dataclass\n\n```python\nfrom typing import Protocol\nfrom dataclasses import dataclass\n\nclass PricingStrategy(Protocol):\n    def price(self, base: float) -> float: ...\n\nclass NoDiscount:\n    def price(self, base): return base\n\nclass PercentOff:\n    def __init__(self, pct: float): self.pct = pct\n    def price(self, base): return base * (1 - self.pct \u002F 100)\n\nclass BlackFriday:\n    def price(self, base): return base * 0.5\n\n@dataclass\nclass Order:\n    items_total: float\n    strategy: PricingStrategy\n    def total(self) -> float:\n        return self.strategy.price(self.items_total)\n\nprint(Order(100, PercentOff(20)).total())   # 80.0\nprint(Order(100, BlackFriday()).total())    # 50.0\n```\n\n### Пример: Repository pattern (in-memory)\n\n```python\nfrom typing import Protocol, TypeVar\nfrom dataclasses import dataclass\n\nT = TypeVar(\"T\")\n\nclass Repository(Protocol[T]):\n    def add(self, item: T) -> None: ...\n    def get(self, id: int) -> T | None: ...\n    def list(self) -> list[T]: ...\n\n@dataclass\nclass User: id: int; name: str\n\nclass InMemoryUserRepo:\n    def __init__(self): self._data: dict[int, User] = {}\n    def add(self, u: User): self._data[u.id] = u\n    def get(self, id: int) -> User | None: return self._data.get(id)\n    def list(self) -> list[User]: return list(self._data.values())\n```\n\n### Пример: `@property` и валидация\n\n```python\nclass Temperature:\n    def __init__(self, celsius: float):\n        self.celsius = celsius   # пройдёт через setter\n\n    @property\n    def celsius(self) -> float:\n        return self._c\n\n    @celsius.setter\n    def celsius(self, v: float) -> None:\n        if v \u003C -273.15:\n            raise ValueError(\"ниже абсолютного нуля\")\n        self._c = v\n\n    @property\n    def kelvin(self) -> float:\n        return self._c + 273.15\n```\n\n### 🛠 Проекты этапа 3\n\n1. **Геометрия**: набор фигур через `Protocol` (без жёсткой иерархии).\n2. **In-memory ORM** (~200 строк): `Repository[T]` + dataclass + JSON-сериализация.\n3. **Парсер выражений** в стиле Visitor.\n4. **Игра «крестики-нолики»**: разделить домен, UI и контроллер.\n\n### 📚 Бесплатные ресурсы этапа 3\n\n- 📘 [Refactoring.guru — паттерны на Python](https:\u002F\u002Frefactoring.guru\u002Fdesign-patterns\u002Fpython).\n- 📘 [faif\u002Fpython-patterns (GitHub)](https:\u002F\u002Fgithub.com\u002Ffaif\u002Fpython-patterns) — каталог.\n- 🎥 [ArjanCodes — Design Patterns in Python](https:\u002F\u002Fwww.youtube.com\u002F@ArjanCodes\u002Fplaylists).\n- 📝 [SOLID на русском (Habr, серия)](https:\u002F\u002Fhabr.com\u002Fru\u002Farticles\u002F688530\u002F).\n- 📘 [Real Python — OOP in Python 3](https:\u002F\u002Frealpython.com\u002Fpython3-object-oriented-programming\u002F).\n- 📘 [Python Type Hints — Protocol vs ABC](https:\u002F\u002Frealpython.com\u002Fpython-protocol\u002F).\n- 💬 [t.me\u002Fpythonl](https:\u002F\u002Ft.me\u002Fpythonl) — разборы реальных рефакторингов.\n\n### ✅ Чеклист этапа 3\n\n- [ ] Объясняю разницу `@classmethod` \u002F `@staticmethod` \u002F instance method\n- [ ] Реализовал ≥ 5 GoF-паттернов на практике\n- [ ] Использую `Protocol` вместо ABC, где это уместно\n- [ ] Понимаю MRO в diamond-наследовании\n- [ ] Знаю минимум 8 dunder-методов наизусть\n- [ ] Применяю SOLID при разборе чужого кода\n\n---\n\n## Этап 4. Типизация\n\n> 🎯 **Цель:** проходить `pyright --strict` без `Any`. Это норма 2026.\n> ⏱ **Время:** 2 недели.\n\n### Карта типов\n\n```\n            ┌─────── СТАТИЧЕСКАЯ ───────┐    ┌─── RUNTIME ───┐\n            │ pyright \u002F mypy            │    │ Pydantic v2   │\n            │ (checker, не runtime!)    │    │ TypeAdapter   │\n            └────────────┬──────────────┘    └───────┬───────┘\n                         │                           │\n       ┌─────────────────┴──────────────┐            │\n       ▼                                ▼            ▼\n┌────────────┐                   ┌────────────┐   ┌─────────────────┐\n│ Generics   │                   │ Protocol   │   │ Валидация ввода │\n│ PEP 695    │                   │ TypedDict  │   │ API, конфиги    │\n│ TypeVar    │                   │ Literal    │   │ настройки       │\n│ ParamSpec  │                   │ Final      │   └─────────────────┘\n└────────────┘                   └────────────┘\n```\n\n### Темы\n\n- Базовые типы: `list[int]`, `dict[str, T]`, `Callable[[int], str]`, `Iterable[T]`.\n- **PEP 695 generics**: `class Stack[T]: ...`, `def first[T](xs: list[T]) -> T`.\n- `TypeVar`, `ParamSpec`, `Concatenate` (для декораторов).\n- `Protocol`, structural subtyping.\n- `Literal`, `Final`, `TypedDict`, `NotRequired`, `Required`.\n- `Annotated[T, ...]` — метаданные для FastAPI \u002F Pydantic.\n- `Self`, `@override` (PEP 698), `assert_type`, `reveal_type`.\n- pyright strict mode, точечные `# type: ignore[error-code]`.\n- **Pydantic v2** — runtime-валидация + сериализация.\n- `TypeGuard` и `TypeIs` (PEP 742) для сужения типов.\n\n### Пример: новые generics (PEP 695)\n\n```python\nclass Stack[T]:\n    def __init__(self) -> None:\n        self._items: list[T] = []\n    def push(self, x: T) -> None: self._items.append(x)\n    def pop(self) -> T: return self._items.pop()\n\ndef first[T](xs: list[T]) -> T | None:\n    return xs[0] if xs else None\n\ns: Stack[int] = Stack()\ns.push(1); s.push(2)\n```\n\n### Пример: Pydantic v2\n\n```python\nfrom pydantic import BaseModel, EmailStr, Field, field_validator\n\nclass User(BaseModel):\n    id: int\n    email: EmailStr\n    age: int = Field(ge=0, le=150)\n    tags: list[str] = []\n\n    @field_validator(\"tags\")\n    @classmethod\n    def tags_lowercase(cls, v: list[str]) -> list[str]:\n        return [t.lower() for t in v]\n\nu = User.model_validate({\"id\": 1, \"email\": \"a@b.c\", \"age\": 30, \"tags\": [\"A\", \"B\"]})\nprint(u.model_dump_json())\n```\n\n### Пример: TypedDict + NotRequired\n\n```python\nfrom typing import TypedDict, NotRequired\n\nclass UserDict(TypedDict):\n    id: int\n    name: str\n    email: NotRequired[str]\n\ndef greet(u: UserDict) -> str:\n    return f\"Hello, {u['name']}!\"\n```\n\n### Пример: TypeGuard\n\n```python\nfrom typing import TypeGuard\n\ndef is_str_list(xs: list[object]) -> TypeGuard[list[str]]:\n    return all(isinstance(x, str) for x in xs)\n\ndef process(xs: list[object]) -> None:\n    if is_str_list(xs):\n        # здесь pyright знает, что xs: list[str]\n        print(\",\".join(xs))\n```\n\n### Пример: `ParamSpec` для декоратора\n\n```python\nfrom typing import ParamSpec, TypeVar, Callable\nfrom functools import wraps\n\nP = ParamSpec(\"P\")\nR = TypeVar(\"R\")\n\ndef log_call(fn: Callable[P, R]) -> Callable[P, R]:\n    @wraps(fn)\n    def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:\n        print(f\"calling {fn.__name__}\")\n        return fn(*args, **kwargs)\n    return wrapper\n```\n\n### 🛠 Практика\n\n- Перевести проект этапа 3 на `pyright --strict` без единого `Any` и подавлений.\n- Написать generic-репозиторий `Repository[T]` с CRUD.\n- Описать схему API через `TypedDict` + Pydantic.\n- Реализовать декоратор `@log_call`, корректно типизированный через `ParamSpec`.\n\n### 📚 Бесплатные ресурсы этапа 4\n\n- 📘 [typing — official docs](https:\u002F\u002Fdocs.python.org\u002F3\u002Flibrary\u002Ftyping.html).\n- 📘 [mypy cheat sheet](https:\u002F\u002Fmypy.readthedocs.io\u002Fen\u002Fstable\u002Fcheat_sheet_py3.html).\n- 📘 [pyright docs](https:\u002F\u002Fmicrosoft.github.io\u002Fpyright\u002F).\n- 📘 [Pydantic v2 docs](https:\u002F\u002Fdocs.pydantic.dev\u002Flatest\u002F).\n- 📘 [PEP 695 — type parameters syntax](https:\u002F\u002Fpeps.python.org\u002Fpep-0695\u002F).\n- 📘 [PEP 742 — TypeIs](https:\u002F\u002Fpeps.python.org\u002Fpep-0742\u002F).\n- 🎥 [mCoding — Python typing](https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=dgBCEB2jVU0).\n- 📝 [Glyph: \"Why Type Hints\"](https:\u002F\u002Fblog.glyph.im\u002F).\n- 💬 [t.me\u002Fpythonl](https:\u002F\u002Ft.me\u002Fpythonl) — посты-разборы новых PEP по типам.\n\n### ✅ Чеклист этапа 4\n\n- [ ] Проект проходит `pyright --strict`\n- [ ] Использую generics в синтаксисе PEP 695\n- [ ] Понимаю разницу `Protocol` vs ABC по применению\n- [ ] Умею писать кастомные валидаторы Pydantic\n- [ ] Знаю, когда нужен `TypedDict`, а когда `dataclass`\n- [ ] Применяю `TypeGuard` \u002F `TypeIs` для сужения типов\n\n---\n\n## Этап 5. Стандартная библиотека\n\n> 🎯 **Цель:** «если функция есть в stdlib — не тащи зависимость».\n> ⏱ **Время:** 3 недели.\n\n### Карта stdlib (must-know)\n\n```\n                          ┌─── STDLIB ESSENTIALS ───┐\n                          │                         │\n        ┌─── Работа ──┐   │   ┌─── Данные ───┐      │  ┌─── I\u002FO ────┐\n        │ pathlib     │   │   │ collections  │      │  │ json\u002Fcsv   │\n        │ shutil      │   │   │ dataclasses  │      │  │ tomllib    │\n        │ tempfile    │   │   │ enum         │      │  │ pickle     │\n        │ subprocess  │   │   │ datetime     │      │  │ sqlite3    │\n        └─────────────┘   │   │ zoneinfo     │      │  └────────────┘\n                          │   │ Decimal      │\n        ┌─── CLI ─────┐   │   └──────────────┘      │  ┌── Crypto ──┐\n        │ argparse    │   │                         │  │ hashlib    │\n        │ logging     │   │   ┌── Functional ──┐    │  │ hmac       │\n        │ contextlib  │   │   │ itertools      │    │  │ secrets    │\n        └─────────────┘   │   │ functools      │    │  └────────────┘\n                          │   │ operator       │\n                          │   └────────────────┘\n                          │\n                          │   ┌── Concurrent ──┐\n                          │   │ threading      │\n                          │   │ multiprocessing│\n                          │   │ asyncio        │\n                          │   │ concurrent.fut │\n                          │   └────────────────┘\n```\n\n### Темы детально\n\n| Модуль | Что освоить |\n|---|---|\n| `pathlib` | `Path`, `\u002F`, `rglob`, `read_text`, `write_bytes` |\n| `collections` | `Counter`, `defaultdict`, `deque`, `ChainMap` |\n| `dataclasses` | `@dataclass`, `field`, `slots=True`, `frozen=True` |\n| `enum` | `Enum`, `StrEnum`, `IntEnum`, `Flag` |\n| `datetime` + `zoneinfo` | таймзоны, ISO 8601, арифметика дат |\n| `re` | группы, `(?P\u003Cname>...)`, `re.compile` |\n| `json` \u002F `tomllib` \u002F `csv` | сериализация, дефолтные decoder\u002Fencoder |\n| `subprocess` | `run(check=True)`, `capture_output`, безопасно |\n| `logging` | `dictConfig`, JSON-формат, уровни |\n| `argparse` \u002F `typer` \u002F `click` | CLI |\n| `concurrent.futures` | `ThreadPoolExecutor`, `ProcessPoolExecutor` |\n| `sqlite3` | embedded SQL, context manager |\n| `secrets` \u002F `hashlib` \u002F `hmac` | пароли, токены, подписи |\n\n### Пример: pathlib\n\n```python\nfrom pathlib import Path\n\nroot = Path(__file__).resolve().parent\ndata_dir = root \u002F \"data\"\ndata_dir.mkdir(exist_ok=True)\n\n# Все .py больше 10 КБ\nfor py in root.rglob(\"*.py\"):\n    if py.stat().st_size > 10_000:\n        print(py.relative_to(root))\n```\n\n### Пример: logging.dictConfig (JSON-логи)\n\n```python\nimport logging\nimport logging.config\n\nlogging.config.dictConfig({\n    \"version\": 1,\n    \"disable_existing_loggers\": False,\n    \"formatters\": {\n        \"json\": {\"format\": '{\"ts\":\"%(asctime)s\",\"lvl\":\"%(levelname)s\",\"msg\":\"%(message)s\",\"logger\":\"%(name)s\"}'},\n    },\n    \"handlers\": {\n        \"stdout\": {\"class\": \"logging.StreamHandler\", \"formatter\": \"json\"},\n    },\n    \"root\": {\"level\": \"INFO\", \"handlers\": [\"stdout\"]},\n})\n\nlog = logging.getLogger(\"app\")\nlog.info(\"hello world\")\n```\n\n### Пример: `Counter` + `defaultdict`\n\n```python\nfrom collections import Counter, defaultdict\n\nwords = \"to be or not to be\".split()\nprint(Counter(words).most_common(2))   # [('to', 2), ('be', 2)]\n\ngroups: dict[str, list[int]] = defaultdict(list)\nfor word, length in [(\"a\", 1), (\"ab\", 2), (\"a\", 1)]:\n    groups[word].append(length)\n```\n\n### Пример: datetime + zoneinfo\n\n```python\nfrom datetime import datetime\nfrom zoneinfo import ZoneInfo\n\nmsk = datetime.now(ZoneInfo(\"Europe\u002FMoscow\"))\nny  = msk.astimezone(ZoneInfo(\"America\u002FNew_York\"))\nprint(msk.isoformat(), \"->\", ny.isoformat())\n```\n\n### Пример: безопасный subprocess\n\n```python\nimport subprocess\n\nresult = subprocess.run(\n    [\"git\", \"status\", \"--porcelain\"],\n    capture_output=True, text=True, check=True,\n)\nprint(result.stdout)\n```\n\n### 🛠 Проекты этапа 5\n\n1. **Backup-утилита** (pathlib + tarfile + logging + argparse).\n2. **JSON-конфиг → TOML migrator** с валидацией.\n3. **CLI-tracker привычек** на SQLite.\n4. **Парсер логов nginx** в структурированный JSON.\n5. **Утилита очистки папки** (старше N дней) с dry-run.\n\n### 📚 Бесплатные ресурсы этапа 5\n\n- 📘 [PyMOTW-3 (Python Module of the Week)](https:\u002F\u002Fpymotw.com\u002F3\u002F) — главный справочник.\n- 📘 [docs.python.org\u002F3\u002Flibrary](https:\u002F\u002Fdocs.python.org\u002F3\u002Flibrary\u002F).\n- 📝 [Real Python — pathlib tutorial](https:\u002F\u002Frealpython.com\u002Fpython-pathlib\u002F).\n- 📝 [Real Python — Working with JSON](https:\u002F\u002Frealpython.com\u002Fpython-json\u002F).\n- 🎥 [Anthony Sottile — глубокие разборы stdlib](https:\u002F\u002Fwww.youtube.com\u002F@anthonywritescode).\n- 📝 [Loguru](https:\u002F\u002Fgithub.com\u002FDelgan\u002Floguru) — альтернатива logging (но stdlib знать обязательно).\n- 💬 [t.me\u002Fpythonl](https:\u002F\u002Ft.me\u002Fpythonl) — заметки «фичи stdlib, о которых забыли».\n\n### ✅ Чеклист этапа 5\n\n- [ ] В новом коде не использую `os.path`\n- [ ] Настроил структурированное логирование\n- [ ] Применяю `Counter`\u002F`defaultdict`\u002F`deque` по месту\n- [ ] Прочитал PyMOTW по `itertools`, `functools`, `collections`\n- [ ] Работаю с таймзонами через `zoneinfo`, без `pytz`\n- [ ] Знаю, чем `json.loads` отличается от `json.load`\n\n---\n\n## Этап 6. Асинхронность и конкурентность\n\n> 🎯 **Цель:** не путать concurrency и parallelism. Уверенно писать async-код без race-conditions.\n> ⏱ **Время:** 4 недели.\n\n### Модель конкурентности в Python 2026\n\n```\n                 ┌───── Что у нас в Python ─────┐\n                 │                              │\n   I\u002FO-bound  ───┼──▶ asyncio (1 поток, event loop)\n                 │                              │\n   CPU-bound  ───┼──▶ multiprocessing (N процессов, обходим GIL)\n                 │                              │\n   Mixed\u002Fлегко  ─┼──▶ threading (с GIL — для I\u002FO)\n                 │                              │\n   Без GIL (PEP 703) ─▶ python3.13t threads на CPU — экспериментально\n                 │                              │\n   Structured  ──┼──▶ anyio \u002F trio + TaskGroup\n                 └──────────────────────────────┘\n```\n\n### Когда что выбирать\n\n| Задача | Инструмент |\n|---|---|\n| 1000 HTTP-запросов | `asyncio` + `httpx` |\n| Обработка изображений (CPU) | `ProcessPoolExecutor` |\n| Чтение\u002Fзапись файлов с лимитом | `asyncio.Semaphore` |\n| Парсинг N CSV параллельно | `ProcessPoolExecutor` |\n| Realtime-сервер | `asyncio` + WebSocket |\n| Очередь задач | `arq` \u002F `taskiq` \u002F `dramatiq` \u002F Celery |\n\n### Темы\n\n- Модель **GIL** и **free-threaded** Python (PEP 703).\n- Потоки (`threading`) — когда полезны (I\u002FO, а после 3.13t — и CPU).\n- Процессы (`multiprocessing`, `ProcessPoolExecutor`).\n- **asyncio**: event loop, `await`, `asyncio.TaskGroup` (3.11+), `asyncio.timeout`.\n- **Structured concurrency**: `anyio`, `trio`.\n- Async-контекстные менеджеры, async-итераторы (`async for`, `async with`).\n- HTTP-клиенты: `httpx`, `aiohttp`.\n- БД: `asyncpg`, `aiosqlite`, async SQLAlchemy 2.x.\n- Очереди задач: `arq`, `taskiq`, `dramatiq`, `faststream`, Celery 5.\n- Backpressure, отмена задач, тайм-ауты, retry с экспоненциальным бэкоффом.\n\n### Пример: TaskGroup (3.11+ стиль)\n\n```python\nimport asyncio\nimport httpx\n\nasync def fetch(client: httpx.AsyncClient, url: str) -> int:\n    r = await client.get(url, timeout=5)\n    return len(r.content)\n\nasync def main():\n    urls = [\"https:\u002F\u002Fexample.com\"] * 10\n    async with httpx.AsyncClient() as client:\n        async with asyncio.TaskGroup() as tg:\n            tasks = [tg.create_task(fetch(client, u)) for u in urls]\n    sizes = [t.result() for t in tasks]\n    print(sum(sizes))\n\nasyncio.run(main())\n```\n\n### Пример: Семафор как rate-limiter\n\n```python\nimport asyncio\n\nasync def worker(sem: asyncio.Semaphore, i: int):\n    async with sem:\n        await asyncio.sleep(1)\n        print(f\"done {i}\")\n\nasync def main():\n    sem = asyncio.Semaphore(5)   # максимум 5 одновременно\n    async with asyncio.TaskGroup() as tg:\n        for i in range(20):\n            tg.create_task(worker(sem, i))\n\nasyncio.run(main())\n```\n\n### Пример: `asyncio.timeout` (3.11+)\n\n```python\nimport asyncio\n\nasync def slow():\n    await asyncio.sleep(10); return \"ok\"\n\nasync def main():\n    try:\n        async with asyncio.timeout(1):\n            await slow()\n    except TimeoutError:\n        print(\"timed out\")\n\nasyncio.run(main())\n```\n\n### Пример: retry с экспоненциальным бэкоффом\n\n```python\nimport asyncio\nimport random\n\nasync def with_retry(fn, *, attempts=5, base=0.2):\n    for i in range(1, attempts + 1):\n        try:\n            return await fn()\n        except Exception as e:\n            if i == attempts:\n                raise\n            delay = base * (2 ** (i - 1)) * (1 + random.random())\n            await asyncio.sleep(delay)\n```\n\n### Пример: CPU-задача через процессы\n\n```python\nfrom concurrent.futures import ProcessPoolExecutor\n\ndef heavy(n: int) -> int:\n    return sum(i * i for i in range(n))\n\nif __name__ == \"__main__\":\n    with ProcessPoolExecutor() as pool:\n        results = list(pool.map(heavy, [10_000_000] * 8))\n    print(sum(results))\n```\n\n### 🛠 Проекты этапа 6\n\n1. **Async-краулер** 1000 URL с лимитом, ретраями, метриками.\n2. **WebSocket-чат** на pure asyncio (без фреймворков).\n3. **Очередь задач** на Redis Streams через arq.\n4. **Скан портов** на asyncio + Semaphore.\n5. **Сравнение sync vs async vs процессы** на одной и той же задаче.\n\n### 📚 Бесплатные ресурсы этапа 6\n\n- 📘 [Real Python — Async IO: Complete Walkthrough](https:\u002F\u002Frealpython.com\u002Fasync-io-python\u002F).\n- 📘 [Trio docs — structured concurrency](https:\u002F\u002Ftrio.readthedocs.io\u002F).\n- 📝 [Nathaniel J. Smith — «Notes on structured concurrency»](https:\u002F\u002Fvorpus.org\u002Fblog\u002Fnotes-on-structured-concurrency-or-go-statement-considered-harmful\u002F).\n- 🎥 [David Beazley — Python Concurrency from the Ground Up](https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=MCs5OvhV9S4).\n- 📘 [PEP 703 — Making GIL Optional](https:\u002F\u002Fpeps.python.org\u002Fpep-0703\u002F).\n- 📘 [httpx docs](https:\u002F\u002Fwww.python-httpx.org\u002F) \u002F [aiohttp docs](https:\u002F\u002Fdocs.aiohttp.org\u002F).\n- 🎥 [mCoding — async\u002Fawait explained](https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=GpqAQxH1Afc).\n- 💬 [t.me\u002Fpythonl](https:\u002F\u002Ft.me\u002Fpythonl) — посты про asyncio, GIL, JIT.\n\n### ✅ Чеклист этапа 6\n\n- [ ] Объясняю concurrency vs parallelism\n- [ ] Пишу async-код через TaskGroup, а не `gather`\n- [ ] Применяю `asyncio.timeout` и Semaphore по месту\n- [ ] Реализовал retry с экспоненциальным бэкоффом\n- [ ] Понимаю, когда нужен `asyncio`, а когда `ProcessPoolExecutor`\n- [ ] Знаю, как корректно отменить задачу и обработать `CancelledError`\n\n---\n\n## Этап 7. Тестирование и качество кода\n\n> 🎯 **Цель:** ваш код проходит CI без вашего участия. Покрытие — не цель, а побочный эффект.\n> ⏱ **Время:** 2 недели.\n\n### Пирамида тестов\n\n```\n                     ┌──────────────┐\n                     │  E2E (мало)  │\n                     ├──────────────┤\n                     │ Integration  │\n                     │ (среднее)    │\n                     ├──────────────┤\n                     │ Unit (много) │\n                     └──────────────┘\n   Скорость:        ↑ медленно       ↓ быстро\n   Стоимость:       ↑ дорого         ↓ дёшево\n   Стабильность:    ↓ флакает        ↑ стабильно\n```\n\n### Темы\n\n- **pytest**: фикстуры, параметризация, маркеры, `conftest.py`, плагины.\n- Плагины: `pytest-asyncio`, `pytest-mock`, `pytest-cov`, `pytest-xdist`, `pytest-randomly`.\n- **Hypothesis** — property-based testing.\n- Моки\u002Fстабы\u002Fфейки. **TestContainers** для интеграционных тестов.\n- Покрытие ≥ 80%, но edge-cases важнее цифры.\n- Mutation testing: `mutmut`, `cosmic-ray`.\n- Линтеры: ruff, pyright, bandit (security), vulture (dead code), pip-audit.\n- pre-commit + GitHub Actions.\n\n### Пример: параметризация\n\n```python\nimport pytest\n\n@pytest.mark.parametrize(\"a,b,expected\", [\n    (1, 2, 3),\n    (-1, 1, 0),\n    (0, 0, 0),\n])\ndef test_add(a, b, expected):\n    assert a + b == expected\n```\n\n### Пример: фикстура с teardown\n\n```python\nimport pytest, sqlite3\n\n@pytest.fixture\ndef db():\n    conn = sqlite3.connect(\":memory:\")\n    conn.execute(\"CREATE TABLE users (id INTEGER, name TEXT)\")\n    yield conn\n    conn.close()\n\ndef test_insert(db):\n    db.execute(\"INSERT INTO users VALUES (1, 'Ann')\")\n    rows = db.execute(\"SELECT * FROM users\").fetchall()\n    assert rows == [(1, \"Ann\")]\n```\n\n### Пример: hypothesis\n\n```python\nfrom hypothesis import given, strategies as st\n\ndef reverse(s: str) -> str:\n    return s[::-1]\n\n@given(st.text())\ndef test_reverse_twice_is_identity(s):\n    assert reverse(reverse(s)) == s\n```\n\n### Пример: async-тест\n\n```python\nimport pytest, asyncio\n\n@pytest.mark.asyncio\nasync def test_sleep():\n    start = asyncio.get_event_loop().time()\n    await asyncio.sleep(0.1)\n    assert asyncio.get_event_loop().time() - start >= 0.1\n```\n\n### Пример: GitHub Actions CI\n\n```yaml\n# .github\u002Fworkflows\u002Fci.yml\nname: CI\non: [push, pull_request]\njobs:\n  test:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        python: [\"3.13\"]\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - uses: astral-sh\u002Fsetup-uv@v3\n        with:\n          python-version: ${{ matrix.python }}\n      - run: uv sync --all-extras\n      - run: uv run ruff check .\n      - run: uv run pyright\n      - run: uv run pytest --cov --cov-report=xml\n```\n\n### 🛠 Практика этапа 7\n\n- Покрыть тестами проект этапа 5 на 90%+.\n- Добавить ≥ 5 property-based тестов через hypothesis.\n- Настроить mutation testing — снизить выживших мутантов до \u003C 20%.\n- Запустить TestContainers с Postgres и проверить интеграцию.\n\n### 📚 Бесплатные ресурсы этапа 7\n\n- 📘 [pytest docs](https:\u002F\u002Fdocs.pytest.org\u002F).\n- 📘 [Hypothesis docs](https:\u002F\u002Fhypothesis.readthedocs.io\u002F).\n- 📝 [Brian Okken — Python Testing with pytest (free chapters)](https:\u002F\u002Fpythontest.com\u002F).\n- 🎥 [Test & Code podcast](https:\u002F\u002Ftestandcode.com\u002F).\n- 🎥 [Anthony Sottile — pytest deep-dives](https:\u002F\u002Fwww.youtube.com\u002F@anthonywritescode).\n- 📘 [Awesome pytest plugins](https:\u002F\u002Fgithub.com\u002Faugustogoulart\u002Fawesome-pytest).\n- 💬 [t.me\u002Fpythonl](https:\u002F\u002Ft.me\u002Fpythonl) — обзоры подходов к тестированию.\n\n### ✅ Чеклист этапа 7\n\n- [ ] Покрытие тестами > 80%\n- [ ] Есть минимум 3 property-based теста\n- [ ] CI собирает: lint + typecheck + tests + coverage\n- [ ] Pre-commit запускается при каждом коммите\n- [ ] Использую `pytest-xdist` для параллельного запуска\n- [ ] Понимаю разницу mock \u002F stub \u002F fake \u002F spy\n\n---\n\n## Этап 8. Внутренности CPython\n\n> 🎯 **Цель:** понимать, **как Python работает изнутри**. Это отличает Middle от Senior.\n> ⏱ **Время:** 2–3 недели.\n\n### Архитектура CPython (упрощённо)\n\n```\n   .py файл\n      │  (compile)\n      ▼\n   .pyc байткод  ──▶  ┌──────────────────────┐\n                      │ Specializing Adaptive│\n                      │ Interpreter (PEP 659)│\n                      └──────────┬───────────┘\n                                 │\n                                 ▼\n                      ┌──────────────────────┐\n                      │ JIT (PEP 744, 3.13+) │\n                      └──────────┬───────────┘\n                                 │\n                                 ▼\n                       Объектная модель:\n                       PyObject* + refcount\n                                 │\n                                 ▼\n                       GC (циклический)\n                                 │\n                       ┌─────────┴─────────┐\n                       │      GIL          │\n                       │  free-threaded?   │\n                       │   (PEP 703)       │\n                       └───────────────────┘\n```\n\n### Темы\n\n- Объектная модель: всё — `PyObject*`.\n- **Reference counting** + циклический GC.\n- Байткод: `dis.dis(fn)`, peephole-оптимизации.\n- **Specializing Adaptive Interpreter** (PEP 659) с 3.11.\n- **JIT** (PEP 744) в 3.13+ — что ускоряется, что нет.\n- **GIL** и free-threaded build (PEP 703).\n- C-API на пальцах: CPython vs PyPy vs GraalPy.\n- Профилирование: `cProfile`, `py-spy`, `scalene`, `memray`, `viztracer`.\n\n### Пример: разбор байткода\n\n```python\nimport dis\n\ndef add(a, b):\n    return a + b\n\ndis.dis(add)\n# LOAD_FAST a\n# LOAD_FAST b\n# BINARY_OP +\n# RETURN_VALUE\n```\n\n### Пример: измерение памяти\n\n```python\nimport sys\nprint(sys.getsizeof([1, 2, 3]))     # 88\nprint(sys.getsizeof((1, 2, 3)))     # 64 — tuple компактнее\nprint(sys.getsizeof(\"abc\"))         # 52\n```\n\n### Пример: `__slots__` экономит память\n\n```python\nclass A:\n    def __init__(self): self.x = 1; self.y = 2\n\nclass B:\n    __slots__ = (\"x\", \"y\")\n    def __init__(self): self.x = 1; self.y = 2\n\nimport sys\nprint(sys.getsizeof(A().__dict__))   # ~104\n# у B нет __dict__, экономия ~40-50% на больших коллекциях объектов\n```\n\n### Пример: профилирование py-spy\n\n```bash\npip install py-spy   # или uv add --dev py-spy\n\n# Флеймграф продакшна\npy-spy record -o profile.svg -- python my_app.py\n\n# Live top по работающему процессу\npy-spy top --pid 12345\n```\n\n### Пример: memray для памяти\n\n```bash\npip install memray\npython -m memray run my_app.py\npython -m memray flamegraph memray-my_app.bin\n```\n\n### 🛠 Проекты этапа 8\n\n- Взять «медленный» скрипт и **ускорить в 10×**. Зафиксировать до\u002Fпосле через `py-spy` + `memray`.\n- Перевести узкий цикл на NumPy\u002FPolars, замерить разницу.\n- Сравнить производительность CPython 3.13 vs PyPy на одной задаче.\n\n### 📚 Бесплатные ресурсы этапа 8\n\n- 📘 [«Inside The Python Virtual Machine» (free online)](https:\u002F\u002Fleanpub.com\u002Finsidethepythonvirtualmachine\u002Fread).\n- 📝 [tenthousandmeters.com — \"Python behind the scenes\" (серия)](https:\u002F\u002Ftenthousandmeters.com\u002F).\n- 📘 [PEP 659 — Specializing Adaptive Interpreter](https:\u002F\u002Fpeps.python.org\u002Fpep-0659\u002F).\n- 📘 [PEP 744 — JIT compilation](https:\u002F\u002Fpeps.python.org\u002Fpep-0744\u002F).\n- 📘 [PEP 703 — Making GIL Optional](https:\u002F\u002Fpeps.python.org\u002Fpep-0703\u002F).\n- 🎥 [Łukasz Langa — keynote talks про CPython](https:\u002F\u002Fwww.youtube.com\u002Fresults?search_query=lukasz+langa+keynote).\n- 📝 [Real Python — Memory Management in Python](https:\u002F\u002Frealpython.com\u002Fpython-memory-management\u002F).\n- 📘 [py-spy на GitHub](https:\u002F\u002Fgithub.com\u002Fbenfred\u002Fpy-spy) \u002F [memray](https:\u002F\u002Fgithub.com\u002Fbloomberg\u002Fmemray).\n- 💬 [t.me\u002Fpythonl](https:\u002F\u002Ft.me\u002Fpythonl) — разборы релизов CPython.\n\n### ✅ Чеклист этапа 8\n\n- [ ] Читаю и понимаю вывод `dis`\n- [ ] Профилировал реальный код через py-spy и memray\n- [ ] Объясняю, почему GIL — это не «питон медленный»\n- [ ] Понимаю работу specializing interpreter\n- [ ] Знаю, когда применить `__slots__`\n- [ ] Сравнил CPython vs PyPy на собственной задаче\n\n---\n\n## Этап 9. Web-разработка\n\n> 🎯 **Цель:** собрать production-ready API с авторизацией, БД, тестами и документацией.\n> ⏱ **Время:** 4–5 недель.\n\n### Стек 2026 (схема)\n\n```\n   Клиент (Browser \u002F Mobile \u002F SPA \u002F HTMX)\n       │\n       ▼  HTTPS\n   ┌────────────────────────────────────────┐\n   │  Reverse Proxy \u002F Load Balancer         │\n   │  (nginx \u002F Caddy \u002F Traefik)             │\n   └────────────────────────────────────────┘\n       │\n       ▼  ASGI\n   ┌────────────────────────────────────────┐\n   │  ASGI server                           │\n   │  granian (Rust) \u002F uvicorn \u002F hypercorn  │\n   └────────────────────────────────────────┘\n       │\n       ▼\n   ┌────────────────────────────────────────┐\n   │  Framework: FastAPI \u002F Litestar \u002FDjango │\n   │  Pydantic v2  •  OpenAPI  •  DI        │\n   └────────────────────────────────────────┘\n       │\n       ▼\n   ┌─────────────┐  ┌─────────────┐  ┌─────────────┐\n   │ PostgreSQL  │  │   Redis     │  │  S3 \u002F MinIO │\n   └─────────────┘  └─────────────┘  └─────────────┘\n```\n\n### Базис\n\n- HTTP\u002F1.1, HTTP\u002F2, HTTP\u002F3, WebSockets, Server-Sent Events.\n- REST, gRPC, GraphQL (strawberry), JSON-RPC.\n- OpenAPI 3.1, JSON Schema.\n- Cookies, sessions, JWT, OAuth2, OIDC, PASETO.\n\n### Фреймворки 2026\n\n| Фреймворк | Когда выбирать |\n|---|---|\n| **FastAPI** | API, микросервисы, async — топ-выбор |\n| **Litestar** | FastAPI-альтернатива с DI и плагинами |\n| **Django 5.x** | большой монолит, админка, ORM «из коробки» |\n| **Starlette** | свой ASGI-фундамент, минимализм |\n| **Granian** | самый быстрый ASGI-сервер (Rust) |\n\n### Пример: FastAPI hello\n\n```python\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI(title=\"Tasks API\")\n\nclass Task(BaseModel):\n    id: int\n    title: str\n    done: bool = False\n\nDB: dict[int, Task] = {}\n\n@app.get(\"\u002Ftasks\", response_model=list[Task])\ndef list_tasks() -> list[Task]:\n    return list(DB.values())\n\n@app.post(\"\u002Ftasks\", response_model=Task, status_code=201)\ndef create_task(task: Task) -> Task:\n    DB[task.id] = task\n    return task\n```\n\nЗапуск: `uvicorn main:app --reload` → http:\u002F\u002Flocalhost:8000\u002Fdocs\n\n### Пример: DI и авторизация\n\n```python\nfrom fastapi import Depends, HTTPException, Header\n\ndef auth_user(authorization: str = Header()) -> str:\n    if not authorization.startswith(\"Bearer \"):\n        raise HTTPException(401, \"Unauthorized\")\n    return authorization.removeprefix(\"Bearer \")\n\n@app.get(\"\u002Fme\")\ndef me(token: str = Depends(auth_user)) -> dict:\n    return {\"token\": token}\n```\n\n### Пример: WebSocket-эхо\n\n```python\nfrom fastapi import FastAPI, WebSocket\n\napp = FastAPI()\n\n@app.websocket(\"\u002Fws\")\nasync def ws_echo(ws: WebSocket):\n    await ws.accept()\n    try:\n        while True:\n            msg = await ws.receive_text()\n            await ws.send_text(f\"echo: {msg}\")\n    except Exception:\n        await ws.close()\n```\n\n### Пример: rate-limiter на Redis (псевдо-код)\n\n```python\nasync def rate_limited(redis, user_id: str, limit: int = 100) -> bool:\n    key = f\"rl:{user_id}\"\n    count = await redis.incr(key)\n    if count == 1:\n        await redis.expire(key, 60)\n    return count \u003C= limit\n```\n\n### 🛠 Проекты этапа 9\n\n1. **Task Tracker API**: FastAPI + Postgres + Redis + JWT + OpenAPI + Docker.\n2. **URL-shortener**: FastAPI + Redis + статистика кликов.\n3. **Реалтайм чат**: FastAPI WebSocket + Redis Pub\u002FSub.\n4. **OAuth2 интеграция** с GitHub login.\n\n### 📚 Бесплатные ресурсы этапа 9\n\n- 📘 [FastAPI docs](https:\u002F\u002Ffastapi.tiangolo.com\u002F) — образцовая документация.\n- 📘 [Litestar docs](https:\u002F\u002Fdocs.litestar.dev\u002F).\n- 📘 [Django docs](https:\u002F\u002Fdocs.djangoproject.com\u002F).\n- 📘 [Django Girls Tutorial (RU)](https:\u002F\u002Ftutorial.djangogirls.org\u002Fru\u002F) — для новичков в Django.\n- 🎥 [ArjanCodes — FastAPI series](https:\u002F\u002Fwww.youtube.com\u002F@ArjanCodes\u002Fsearch?query=fastapi).\n- 📝 [TestDriven.io blog](https:\u002F\u002Ftestdriven.io\u002Fblog\u002F) — много бесплатных туториалов.\n- 📘 [MDN HTTP docs](https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FHTTP).\n- 📘 [Awesome FastAPI](https:\u002F\u002Fgithub.com\u002Fmjhea0\u002Fawesome-fastapi).\n- 💬 [t.me\u002Fpythonl](https:\u002F\u002Ft.me\u002Fpythonl) — разборы новых web-фич.\n\n### ✅ Чеклист этапа 9\n\n- [ ] Запустил FastAPI с авторизацией, БД и Swagger\n- [ ] Понимаю WSGI vs ASGI\n- [ ] Знаю, что делает CORS и зачем\n- [ ] Реализовал rate-limiting\n- [ ] Написал WebSocket-эндпоинт\n- [ ] Завернул API в Docker\n\n---\n\n## Этап 10. Базы данных и ORM\n\n> 🎯 **Цель:** уверенно писать SQL, читать `EXPLAIN ANALYZE`, использовать ORM как инструмент, а не магию.\n> ⏱ **Время:** 3 недели.\n\n### Карта\n\n```\n              ┌─────── ХРАНЕНИЕ ДАННЫХ ───────┐\n              │                               │\n   ┌──────────┴────────┐         ┌────────────┴────────┐\n   │ Реляционные SQL   │         │      NoSQL          │\n   ├───────────────────┤         ├─────────────────────┤\n   │ PostgreSQL 17+    │         │ Redis (kv, queues)  │\n   │ SQLite (embedded) │         │ MongoDB (docs)      │\n   │ MySQL \u002F MariaDB   │         │ ClickHouse (OLAP)   │\n   └───────┬───────────┘         │ Qdrant (vectors)    │\n           │                     └─────────────────────┘\n           ▼\n   ┌────────────────────┐         ┌─────────────────────┐\n   │  ORM \u002F Toolkit     │         │     Поиск           │\n   │  SQLAlchemy 2.x    │         │ Meilisearch         │\n   │  SQLModel          │         │ Typesense           │\n   │  Piccolo \u002F Tortoise│         │ Elasticsearch       │\n   └─────────┬──────────┘         └─────────────────────┘\n             │\n             ▼\n   ┌────────────────────┐\n   │ Миграции: Alembic  │\n   └────────────────────┘\n```\n\n### Темы\n\n- **SQL**: SELECT\u002FJOIN\u002FGROUP BY\u002FHAVING, индексы, CTE, оконные функции.\n- **PostgreSQL 17+** — основной выбор. SQLite — для embedded.\n- **SQLAlchemy 2.x** (Core + ORM, async).\n- Альтернативы: SQLModel, Tortoise, Piccolo.\n- Миграции: **Alembic**.\n- Pooling: PgBouncer, встроенный pool.\n- NoSQL: Redis, MongoDB, ClickHouse.\n- Поиск: Meilisearch \u002F Typesense \u002F Elasticsearch.\n\n### Пример: SQLAlchemy 2.x async ORM\n\n```python\nfrom sqlalchemy import String, select\nfrom sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker\nfrom sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column\n\nclass Base(DeclarativeBase): pass\n\nclass User(Base):\n    __tablename__ = \"users\"\n    id: Mapped[int] = mapped_column(primary_key=True)\n    email: Mapped[str] = mapped_column(String(255), unique=True)\n\nengine = create_async_engine(\"postgresql+asyncpg:\u002F\u002Fu:p@localhost\u002Fdb\")\nSessionLocal = async_sessionmaker(engine, expire_on_commit=False)\n\nasync def get_user(email: str) -> User | None:\n    async with SessionLocal() as s:\n        result = await s.execute(select(User).where(User.email == email))\n        return result.scalar_one_or_none()\n```\n\n### Пример: оконная функция в SQL\n\n```sql\nSELECT\n    user_id,\n    amount,\n    SUM(amount) OVER (PARTITION BY user_id ORDER BY created_at) AS running_total\nFROM payments;\n```\n\n### Пример: миграция Alembic\n\n```bash\nuv run alembic init migrations\n# редактируем env.py, добавляем target_metadata = Base.metadata\nuv run alembic revision --autogenerate -m \"users\"\nuv run alembic upgrade head\n```\n\n### Пример: индексы и EXPLAIN\n\n```sql\n-- ❌ медленно\nSELECT * FROM users WHERE LOWER(email) = 'a@b.c';\n\n-- ✅ создаём функциональный индекс\nCREATE INDEX users_email_lower ON users (LOWER(email));\n\nEXPLAIN ANALYZE SELECT * FROM users WHERE LOWER(email) = 'a@b.c';\n```\n\n### 🛠 Проекты этапа 10\n\n1. **Аналитический дашборд** поверх ClickHouse + FastAPI + Plotly.\n2. **Полнотекстовый поиск** на Meilisearch с индексацией из Postgres.\n3. **CQRS-репозиторий**: read через async-view, write через aggregate.\n4. **Аудит-лог** через триггеры и outbox-таблицу.\n\n### 📚 Бесплатные ресурсы этапа 10\n\n- 📘 [SQLAlchemy 2.x docs](https:\u002F\u002Fdocs.sqlalchemy.org\u002Fen\u002F20\u002F) — пройти tutorial обязательно.\n- 📘 [PostgreSQL Tutorial](https:\u002F\u002Fwww.postgresqltutorial.com\u002F) — лучший бесплатный курс по PG.\n- 📘 [«Use the Index, Luke!»](https:\u002F\u002Fuse-the-index-luke.com\u002F) — бесплатная книга про индексы.\n- 📘 [Mode SQL Tutorial](https:\u002F\u002Fmode.com\u002Fsql-tutorial\u002F) — интерактивно.\n- 🎮 [SQLBolt](https:\u002F\u002Fsqlbolt.com\u002F) — короткие уроки + задачи.\n- 📘 [Alembic docs](https:\u002F\u002Falembic.sqlalchemy.org\u002F).\n- 📘 [Designing Data-Intensive Applications — главы автора](https:\u002F\u002Fdataintensive.net\u002F).\n- 💬 [t.me\u002Fpythonl](https:\u002F\u002Ft.me\u002Fpythonl) — посты про SQLAlchemy и Postgres.\n\n### ✅ Чеклист этапа 10\n\n- [ ] Пишу JOIN-ы и оконные функции на SQL без подсказок\n- [ ] Читаю `EXPLAIN ANALYZE` и понимаю seq scan vs index scan\n- [ ] Настроил Alembic-миграции в проекте\n- [ ] Использую асинхронный SQLAlchemy 2.x\n- [ ] Знаю, когда нужен индекс, а когда он вредит\n- [ ] Понимаю уровни изоляции транзакций\n\n---\n\n## Этап 11. Data \u002F ML \u002F AI\n\n> 🎯 **Цель:** уверенно работать с табличными данными и собрать практический RAG\u002FML-проект.\n> ⏱ **Время:** 4–6 недель.\n\n### Карта данных и ML\n\n```\n   ┌──────── ВВОД ────────┐         ┌──────── ОБРАБОТКА ────────┐\n   │ CSV \u002F Parquet \u002F JSON │  ───▶   │ NumPy 2.x                 │\n   │ Postgres \u002F ClickHouse│         │ pandas 2.x (Arrow)        │\n   │ S3 \u002F MinIO           │         │ Polars (lazy, ★★★)        │\n   │ API                  │         │ DuckDB (SQL embedded)     │\n   └──────────────────────┘         └────────────┬──────────────┘\n                                                 │\n                                                 ▼\n                ┌────────────── МОДЕЛИРОВАНИЕ ─────────────┐\n                │  scikit-learn (классика)                 │\n                │  XGBoost \u002F LightGBM \u002F CatBoost (boosting)│\n                │  PyTorch 2.x (DL)                        │\n                │  JAX (исследования)                      │\n                └─────────────────────┬────────────────────┘\n                                      ▼\n                ┌────────────── LLM-стек ──────────────────┐\n                │  LangChain \u002F LlamaIndex \u002F DSPy \u002F Haystack│\n                │  Vector DB: pgvector \u002F Qdrant \u002F Weaviate │\n                │  Embeddings + RAG-пайплайны              │\n                └──────────────────────────────────────────┘\n```\n\n### Темы\n\n- **NumPy 2.x** — основа. Векторизация вместо циклов.\n- **pandas 2.x** (Arrow backend) и **Polars** (must-have, в 5–10× быстрее).\n- **DuckDB** — embedded аналитика, читает CSV\u002FParquet\u002FJSON напрямую.\n- Визуализация: **plotly**, **altair**, **matplotlib**, **seaborn**.\n- Notebooks: Jupyter, **marimo** (реактивные, без .ipynb).\n- ML: scikit-learn, XGBoost, LightGBM, CatBoost.\n- DL: **PyTorch 2.x**, JAX.\n- LLM-стек: **LangChain \u002F LlamaIndex \u002F DSPy \u002F Haystack**.\n- Vector DB: **pgvector**, **Qdrant**, **Weaviate**, **Chroma**.\n- MLOps: MLflow, Weights & Biases, Prefect, Dagster.\n\n### Пример: Polars\n\n```python\nimport polars as pl\n\ndf = pl.read_csv(\"sales.csv\")\nresult = (\n    df.filter(pl.col(\"amount\") > 100)\n      .group_by(\"region\")\n      .agg(pl.col(\"amount\").sum().alias(\"total\"))\n      .sort(\"total\", descending=True)\n)\nprint(result)\n```\n\n### Пример: DuckDB (SQL по CSV)\n\n```python\nimport duckdb\n\nduckdb.sql(\"\"\"\n    SELECT region, SUM(amount) AS total\n    FROM 'sales.csv'\n    WHERE amount > 100\n    GROUP BY region\n    ORDER BY total DESC\n\"\"\").show()\n```\n\n### Пример: scikit-learn baseline\n\n```python\nfrom sklearn.datasets import load_iris\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.ensemble import RandomForestClassifier\n\nX, y = load_iris(return_X_y=True)\nX_tr, X_te, y_tr, y_te = train_test_split(X, y, random_state=42)\nclf = RandomForestClassifier().fit(X_tr, y_tr)\nprint(clf.score(X_te, y_te))\n```\n\n### Пример: RAG (упрощённо)\n\n```python\n# 1. Создаём эмбеддинги документов\n# 2. Кладём в vector DB (например, pgvector)\n# 3. На запрос ищем top-K похожих\n# 4. Подставляем контекст в промпт LLM\n\n# Псевдо-код:\ndocs = load_docs(\".\u002Fknowledge\u002F\")\nembeddings = embed_model.encode(docs)\nvector_db.upsert(docs, embeddings)\n\ndef answer(query: str) -> str:\n    q_emb = embed_model.encode([query])\n    context = vector_db.search(q_emb, k=5)\n    prompt = f\"Context:\\n{context}\\n\\nQuestion: {query}\"\n    return llm.generate(prompt)\n```\n\n### 🛠 Проекты этапа 11\n\n1. **RAG-бот по своей документации**: FastAPI + pgvector + open LLM API.\n2. **Pipeline аналитики**: Polars + DuckDB + дашборд на marimo.\n3. **Классификация табличных данных** (Kaggle): sklearn + XGBoost + MLflow.\n4. **Парсер + NER** с использованием spaCy.\n5. **Бенчмарк pandas vs Polars** на ваших данных.\n\n### 📚 Бесплатные ресурсы этапа 11\n\n- 📘 [«Python Data Science Handbook» — VanderPlas (free)](https:\u002F\u002Fjakevdp.github.io\u002FPythonDataScienceHandbook\u002F).\n- 📘 [«From Python to NumPy» — Nicolas Rougier (free book)](https:\u002F\u002Fwww.labri.fr\u002Fperso\u002Fnrougier\u002Ffrom-python-to-numpy\u002F).\n- 📘 [Polars user guide](https:\u002F\u002Fdocs.pola.rs\u002F).\n- 📘 [DuckDB docs](https:\u002F\u002Fduckdb.org\u002Fdocs\u002F).\n- 🎥 [3Blue1Brown — Neural Networks](https:\u002F\u002Fwww.youtube.com\u002Fplaylist?list=PLZHQObOWTQDNU6R1_67000Dx_ZCJB-3pi) (must-watch).\n- 📘 [«Dive into Deep Learning» — d2l.ai (free book)](https:\u002F\u002Fd2l.ai\u002F).\n- 📘 [Hugging Face Course (free)](https:\u002F\u002Fhuggingface.co\u002Flearn).\n- 📘 [Fast.ai — Practical Deep Learning (free)](https:\u002F\u002Fcourse.fast.ai\u002F).\n- 📘 [Kaggle Learn (бесплатные мини-курсы)](https:\u002F\u002Fwww.kaggle.com\u002Flearn).\n- 📝 [Sebastian Raschka magazine](https:\u002F\u002Fmagazine.sebastianraschka.com\u002F).\n- 💬 [t.me\u002Fpythonl](https:\u002F\u002Ft.me\u002Fpythonl) — обзоры новых ML\u002FAI инструментов.\n\n### ✅ Чеклист этапа 11\n\n- [ ] Освоил Polars, понимаю выгоду vs pandas\n- [ ] Собрал работающий RAG-бот по своей документации\n- [ ] Понимаю векторные эмбеддинги\n- [ ] Знаю, что такое cosine similarity и где она применяется\n- [ ] Прошёл хотя бы 1 курс на Kaggle Learn\n- [ ] Запушил Kaggle-решение и попал в leaderboard\n\n---\n\n## Этап 12. DevOps и продакшн\n\n> 🎯 **Цель:** довести Python-сервис до прод-готовности: контейнер, конфиги, логи, метрики, CI\u002FCD.\n> ⏱ **Время:** 3 недели.\n\n### Карта продакшн-стека\n\n```\n   Код  ──▶  uv lock  ──▶  Docker (multi-stage)  ──▶  Registry\n                                                          │\n                                                          ▼\n                                              ┌────────────────────┐\n                                              │  CI: GitHub Actions│\n                                              │  lint\u002Ftypecheck\u002F   │\n                                              │  test\u002Fbuild\u002Fpush   │\n                                              └─────────┬──────────┘\n                                                        ▼\n                                              ┌────────────────────┐\n                                              │  K8s (Helm\u002FKustom) │\n                                              │  Deploy + HPA      │\n                                              └─────────┬──────────┘\n                                                        ▼\n                ┌───────────────────────────────────────┴────────────────────┐\n                │            OBSERVABILITY                                   │\n                │  structlog (JSON logs) → Loki                              │\n                │  OpenTelemetry traces  → Tempo \u002F Jaeger                    │\n                │  Prometheus metrics    → Grafana                           │\n                │  Sentry (errors)                                           │\n                └────────────────────────────────────────────────────────────┘\n```\n\n### Темы\n\n- **uv** + lock-файлы, reproducible builds.\n- **Docker** multi-stage, distroless \u002F chainguard.\n- Конфиги: `pydantic-settings`, ENV, 12-factor.\n- Логи: **structlog**, JSON-формат.\n- Observability: **OpenTelemetry**, Prometheus, Grafana, Sentry, Jaeger.\n- CI\u002FCD: **GitHub Actions**, GitLab CI.\n- IaC: Terraform \u002F **Pulumi** (на Python!).\n- Kubernetes: Deployment, Service, HPA, ConfigMap, Secret.\n- Безопасность: `bandit`, `pip-audit`, SBOM (cyclonedx-python).\n\n### Пример: Dockerfile (multi-stage + uv)\n\n```dockerfile\n# syntax=docker\u002Fdockerfile:1.9\nFROM python:3.13-slim AS builder\nCOPY --from=ghcr.io\u002Fastral-sh\u002Fuv:latest \u002Fuv \u002Fuvx \u002Fbin\u002F\nWORKDIR \u002Fapp\nCOPY pyproject.toml uv.lock .\u002F\nRUN uv sync --frozen --no-dev\n\nFROM python:3.13-slim\nWORKDIR \u002Fapp\nCOPY --from=builder \u002Fapp\u002F.venv \u002Fapp\u002F.venv\nCOPY src .\u002Fsrc\nENV PATH=\"\u002Fapp\u002F.venv\u002Fbin:$PATH\"\nCMD [\"python\", \"-m\", \"src.app\"]\n```\n\n### Пример: structlog\n\n```python\nimport structlog\n\nlog = structlog.get_logger()\nlog.info(\"user.signup\", user_id=42, plan=\"pro\")\n# {\"event\":\"user.signup\",\"user_id\":42,\"plan\":\"pro\",\"timestamp\":\"...\"}\n```\n\n### Пример: pydantic-settings\n\n```python\nfrom pydantic_settings import BaseSettings, SettingsConfigDict\n\nclass Settings(BaseSettings):\n    model_config = SettingsConfigDict(env_file=\".env\", extra=\"ignore\")\n    db_url: str\n    redis_url: str = \"redis:\u002F\u002Flocalhost\"\n    debug: bool = False\n\nsettings = Settings()\n```\n\n### Пример: OpenTelemetry (минимум)\n\n```python\nfrom opentelemetry import trace\nfrom opentelemetry.sdk.trace import TracerProvider\nfrom opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter\n\nprovider = TracerP","该项目提供了一份详尽的Python学习路线图，旨在帮助学习者从基础到高级全面掌握Python编程技能。它涵盖了从“Hello, World”入门直到成为资深开发者或架构师所需的知识点，并强调了实践、示例代码以及仅使用免费资源进行学习的重要性。技术特点包括支持Python 3.13+版本的新特性如无锁线程模式(PEP 703)、即时编译(PEP 744)，以及异步优先、类型驱动开发等现代编程理念的应用。此外，还特别关注AI基础设施建设。此项目非常适合希望系统性地提升自身Python能力并紧跟最新技术趋势的学习者和开发者参考使用。","2026-06-11 04:01:23","CREATED_QUERY"]