Python Python: обзор языка, экосистема и дорожная карта курса
0%

Python: обзор языка, экосистема и дорожная карта курса

Python: обзор языка, экосистема и дорожная карта курса

Этот трек — не про то, «как написать первый цикл». Основы программирования на Python уже разобраны в курсе «Программирование с нуля», и если вы ещё не различаете список и словарь, начните оттуда. Здесь мы говорим о другом: как язык устроен внутри, почему он ведёт себя именно так, и что нужно уметь, чтобы писать на нём код, который живёт в продакшене годами.

Разница принципиальная. Человек, знающий синтаксис Python, напишет работающий скрипт за час. Человек, знающий модель исполнения Python, объяснит, почему этот скрипт съел 8 ГБ памяти на проде, почему потоки не ускорили его в четыре раза, почему dataclass с дефолтным списком развалился на второй итерации и почему замена цикла на numpy дала ускорение в 60 раз, а замена for на map — ноль. Мы целимся во вторую категорию.

Язык, реализация и почему их важно различать

Первая вещь, ломающая интуицию людей из мира C# или Java: у Python нет отдельной формальной спецификации, которую реализуют конкурирующие вендоры. Есть Language Reference — документ, который довольно точно описывает семантику, — и есть CPython, эталонная реализация на C, которая де-факто и есть определение языка. Всё, что делает CPython, постепенно становится «тем, как работает Python».

Отсюда практическое следствие: часть свойств, которые вы принимаете за свойства языка, на самом деле свойства реализации.

Свойство Это язык или CPython? Почему важно
Отступы вместо скобок Язык Работает везде
Порядок вставки в dict сохраняется Язык с 3.7 (в 3.6 был деталью CPython) Можно полагаться
Подсчёт ссылок, детерминированное освобождение CPython В PyPy файл закроется позже
GIL CPython (и то не всегда с 3.13) Определяет стратегию конкурентности
Кеш малых int от −5 до 256 CPython Ловушка с is

Кроме CPython существуют PyPy (JIT-компиляция, чистый Python бывает быстрее в 5–20 раз), GraalPy на GraalVM, MicroPython для микроконтроллеров. В этом курсе, если не оговорено иное, речь про CPython 3.12+: это то, что стоит на 95 % серверов.

Модель исполнения: что происходит между файлом и результатом

Python часто называют «интерпретируемым», и это полуправда. На самом деле он компилируется в байт-код, а уже байт-код исполняется виртуальной машиной.

Это не абстракция — байт-код можно посмотреть штатным модулем:

import dis

def add(a, b):
    return a + b

dis.dis(add)

Вывод (Python 3.12; номера опкодов и их набор меняются между минорными версиями — это внутреннее API, не полагайтесь на него в коде):

  2           0 RESUME                   0
  3           2 LOAD_FAST                0 (a)
              4 LOAD_FAST                1 (b)
              6 BINARY_OP                0 (+)
             10 RETURN_VALUE

Три вывода из этой картинки, которые пригодятся весь курс:

  1. Стоимость операции — это стоимость опкода плюс стоимость диспетчеризации. a + b — не сложение чисел, а поиск метода __add__ у типа a, вызов, аллокация нового объекта-результата. Отсюда 30–100-кратное отставание от C на арифметике в цикле.
  2. Быстрый Python — это Python, который делает мало опкодов. Вся практическая оптимизация (см. https://courses.digitable.life/post/python/13-performance/) сводится к тому, чтобы цикл уехал внутрь C-кода: sum(), numpy, join, генераторы вместо ручных циклов.
  3. .pyc — это кеш компиляции, а не защита кода. Байт-код тривиально декомпилируется; «скомпилировать Python, чтобы скрыть исходник» — не работает.

Главная идея языка: всё есть объект, имя — это ярлык

Если из всего трека запомнить одно предложение, пусть будет это. В Python не бывает переменных в смысле C — ячеек памяти, куда кладут значение. Есть объекты в куче и имена, которые на них ссылаются.

Имена как ярлыки на объекты в куче CPython

a = [10, 20]
b = a            # не копия! второй ярлык на тот же объект
b.append(30)
print(a)         # [10, 20, 30]
print(a is b)    # True — один и тот же объект
print(id(a) == id(b))  # True

b = [1]          # присваивание перевешивает ярлык, объект не трогает
print(a)         # [10, 20, 30]

Из этой модели растёт половина «странностей» Python — и половина его силы. Объектом является буквально всё: числа, функции, классы, модули, сами типы.

def greet(name: str) -> str:
    return f"Привет, {name}!"

print(type(greet))          # <class 'function'>
greet.calls = 0             # функции — объекты, у них есть __dict__
print(type(int))            # <class 'type'> — класс тоже объект
print(type(type))           # <class 'type'> — и его тип тоже

handlers = {"ru": greet, "en": str.upper}   # функции лежат в словарях как данные
print(handlers["ru"]("мир"))                # Привет, мир!

Именно поэтому в Python не нужны паттерны вроде «Стратегия» в тяжёлом виде: функция первого класса уже есть стратегия. Подробный разбор — в https://courses.digitable.life/post/python/02-data-model/.

Протоколы вместо интерфейсов: почему len(x) работает на вашем классе

Второй столп языка — протоколы (dunder-методы). Встроенные функции и синтаксис не знают о ваших типах ничего; они просто вызывают методы со специальными именами. len(x)type(x).__len__(x), x[i]__getitem__, with x:__enter__/__exit__, for__iter__. Это и есть знаменитая «утиная типизация», только формализованная.

class Deck:
    """Колода карт. Ничего не наследует, но ведёт себя как последовательность."""

    def __init__(self, cards):
        self._cards = list(cards)

    def __len__(self):
        return len(self._cards)

    def __getitem__(self, i):
        return self._cards[i]


deck = Deck(["A", "K", "Q"])
print(len(deck))            # 3        — работает __len__
print(deck[1])              # K        — работает __getitem__
print("Q" in deck)          # True     — in откатывается на перебор через __getitem__
print(list(reversed(deck))) # ['Q', 'K', 'A'] — reversed использует __len__ + __getitem__
print(deck[::-1])           # ['Q', 'K', 'A'] — срез тоже приходит в __getitem__

Два метода — и объект бесплатно получил итерацию, срезы, оператор in, распаковку, работу с random.choice. Это ключевой рычаг проектирования в Python: вы не наследуетесь от базового класса, вы реализуете протокол.

С появлением typing.Protocol (PEP 544) эту неформальную договорённость можно проверять статически — об этом в https://courses.digitable.life/post/python/07-typing/.

Философия: почему код на Python выглядит именно так

import this печатает «Дзен Python» (PEP 20) — 19 афоризмов Тима Питерса, которые реально определяют дизайн-решения языка. Ключевые:

  • Readability counts. Код читают в десятки раз чаще, чем пишут. Отсюда отступы как синтаксис, and/or/not вместо &&/||/!, отсутствие тернарного ?: в С-образном виде.
  • There should be one — and preferably only one — obvious way to do it. Прямая противоположность девизу Perl. Это причина, по которой в языке нет switch в С-стиле, а match появился только в 3.10 и с другой семантикой (структурное сопоставление, PEP 634).
  • Explicit is better than implicit. Отсюда обязательный self, отсюда явный import, отсюда отсутствие неявных приведений "1" + 1.
  • Errors should never pass silently. Unless explicitly silenced. Отсюда культура исключений и почему except: pass — почти всегда баг (https://courses.digitable.life/post/python/08-errors-and-exceptions/).
  • Practicality beats purity. Отсюда GIL, отсюда изменяемые дефолты, отсюда «we’re all consenting adults here»: приватность в Python — соглашение (_name), а не запрет компилятора.

Отдельно стоит EAFPEasier to Ask Forgiveness than Permission. В Python принято пробовать и ловить исключение, а не проверять условия заранее (LBYL):

# LBYL — «посмотри перед прыжком», стиль из C/Java
if "key" in config and config["key"] is not None:
    value = config["key"]

# EAFP — идиоматичный Python: нет гонки между проверкой и использованием
try:
    value = config["key"]
except KeyError:
    value = DEFAULT

EAFP не просто вкусовщина: между if os.path.exists(p) и open(p) файл может исчезнуть, а между if key in d и d[key] другой поток может удалить ключ. Проверка и действие не атомарны — исключение атомарно.

Как выглядит современный идиоматичный Python

Чтобы задать планку на весь курс, вот законченная утилита. Она короткая, но в ней собрано почти всё, что мы будем разбирать: аннотации типов, dataclass, pathlib, генераторные выражения, collections, форматирование, корректный выход из процесса.

"""Топ-N самых частых слов в текстовом файле."""

from __future__ import annotations

import argparse
import re
import sys
from collections import Counter
from dataclasses import dataclass
from pathlib import Path

WORD_RE = re.compile(r"\w+", re.UNICODE)


@dataclass(frozen=True, slots=True)
class WordStat:
    """Неизменяемая запись: frozen даёт хешируемость, slots — экономию памяти."""

    word: str
    count: int
    share: float


def read_words(path: Path) -> list[str]:
    # pathlib вместо конкатенации строк и open/close вручную
    text = path.read_text(encoding="utf-8")
    return [m.group(0).lower() for m in WORD_RE.finditer(text)]


def top_words(words: list[str], n: int) -> list[WordStat]:
    counter = Counter(words)                 # C-реализация, быстрее ручного dict
    total = sum(counter.values()) or 1       # защита от деления на ноль
    return [WordStat(w, c, c / total) for w, c in counter.most_common(n)]


def main() -> int:
    parser = argparse.ArgumentParser(description="Топ слов в файле")
    parser.add_argument("path", type=Path, help="путь к текстовому файлу")
    parser.add_argument("-n", "--top", type=int, default=10, help="сколько слов вывести")
    args = parser.parse_args()

    try:
        words = read_words(args.path)
    except FileNotFoundError:
        print(f"Файл не найден: {args.path}", file=sys.stderr)
        return 1
    except UnicodeDecodeError:
        print(f"Не похоже на текст в UTF-8: {args.path}", file=sys.stderr)
        return 2

    for stat in top_words(words, args.top):
        print(f"{stat.word:<15} {stat.count:>6} {stat.share:>7.2%}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

Запуск: python top_words.py article.txt -n 5. Вывод:

и                   412  4.11%
в                   388  3.87%
python              201  2.01%
на                  177  1.77%
код                  95  0.95%

Обратите внимание на то, чего здесь нет: ручного открытия/закрытия файла, индексных циклов, str(x) + " " + str(y), класса-обёртки ради одного метода, глобального состояния. Это и есть «питоничность» — предмет статьи https://courses.digitable.life/post/python/06-pythonic-idioms/.

Грабли, на которых спотыкаются все

Это не курьёзы, а следствия модели данных. Каждый пункт мы разберём подробно позже, но увидеть их стоит сразу.

1. Изменяемый аргумент по умолчанию. Дефолт вычисляется один раз — при создании функции, а не при каждом вызове.

def append_to(item, target=[]):     # ← так писать нельзя
    target.append(item)
    return target

print(append_to(1))   # [1]
print(append_to(2))   # [1, 2]  ← тот же самый список!

def append_ok(item, target=None):   # ← правильно
    target = [] if target is None else target
    target.append(item)
    return target

2. Позднее связывание в замыканиях. Замыкание захватывает переменную, а не значение.

fns = [lambda: i for i in range(3)]
print([f() for f in fns])           # [2, 2, 2], а не [0, 1, 2]

fns = [lambda i=i: i for i in range(3)]   # приём: зафиксировать через дефолт
print([f() for f in fns])                 # [0, 1, 2]

3. Умножение списка списков. * копирует ссылку, а не содержимое.

grid = [[0] * 3] * 3
grid[0][0] = 1
print(grid)    # [[1, 0, 0], [1, 0, 0], [1, 0, 0]] — три ярлыка на одну строку

grid = [[0] * 3 for _ in range(3)]   # правильно: три разных списка

4. is вместо ==. is сравнивает идентичность объектов. Из-за кеша малых чисел и интернирования строк это иногда «работает» — и тем опаснее.

a, b = 256, 256
print(a is b)     # True  — кеш малых int в CPython
a, b = 257, 257
print(a is b)     # в скрипте True (константы кода), в REPL построчно False

Правило: is — только для None, True, False и синглтонов-сентинелов.

5. Изменение коллекции во время итерации.

xs = [1, 2, 2, 3]
for x in xs:
    if x == 2:
        xs.remove(x)
print(xs)    # [1, 2, 3] — одна двойка выжила: индексы сдвинулись под итератором

6. or для дефолтов ломается на «ложных» значениях.

def connect(timeout=None):
    timeout = timeout or 30      # timeout=0 молча превратится в 30
    timeout = 30 if timeout is None else timeout   # правильно

7. Файл, затеняющий стандартный модуль. Создали в проекте random.py, email.py или types.py — и import random тянет ваш файл. Ошибка выглядит абсолютно мистически. Подробнее про механику импортов — https://courses.digitable.life/post/python/09-modules-and-packaging/.

8. Числа с плавающей точкой. Это не баг Python, а IEEE 754, но всплывает именно тут:

print(0.1 + 0.2)             # 0.30000000000000004
print(0.1 + 0.2 == 0.3)      # False
from decimal import Decimal
print(Decimal("0.1") + Decimal("0.2") == Decimal("0.3"))   # True — для денег только так

Где Python выигрывает, а где проигрывает

Честный разговор о границах. Python — язык-клей и язык-прототип, который вырос в промышленный инструмент, но не стал универсальным.

Сильные стороны:

  • Скорость от идеи до работающего кода. На типовой задаче кода в 2–4 раза меньше, чем на Java или Go. Для исследовательских и продуктовых гипотез это решает.
  • Экосистема данных и ML. numpy, pandas, polars, scikit-learn, PyTorch, JAX — это не «библиотеки для Python», это де-факто индустриальный стандарт, у которого просто нет полноценной альтернативы в других языках (https://courses.digitable.life/post/machine-learning/00-overview/).
  • Роль языка-клея. Python отлично склеивает C, Rust, СУБД, HTTP-сервисы и очереди. Тяжёлая работа уходит в нативный код, Python оркестрирует.
  • Читаемость и низкий порог входа. Код на Python читает аналитик, DevOps и ML-инженер — это редкое свойство, и оно определяет выбор в смешанных командах.
  • Стандартная библиотека. itertools, collections, dataclasses, pathlib, sqlite3, logging, argparse, asyncio — огромный объём готового качественного кода (https://courses.digitable.life/post/python/10-stdlib/).

Слабые стороны — и это надо знать до, а не после:

  • Скорость чистого Python. Тесный цикл на 10 млн итераций: чистый Python — порядка 0,5–1 с, sum(range(...)) — около 0,1 с, numpy — единицы миллисекунд, C — доли миллисекунды. Разрыв в 30–100 раз никуда не денется.
  • Параллелизм по CPU. GIL не даёт двум потокам одновременно исполнять байт-код. Обходы есть (multiprocessing, нативные расширения, с 3.13 — экспериментальные сборки без GIL), но это осознанная работа, а не «просто запусти потоки» (https://courses.digitable.life/post/python/11-concurrency/).
  • Память. Каждый int — отдельный объект на 28 байт, список из миллиона чисел — десятки мегабайт вместо 8 МБ массива. Для больших данных нужен numpy/pandas/Arrow (https://courses.digitable.life/post/python/14-data-stack/).
  • Дистрибуция приложений конечному пользователю. Собрать один надёжный бинарник, как в Go или Rust, тяжело: PyInstaller/Nuitka работают, но это не «go build».
  • Мобильная и десктопная разработка. Формально возможна (Kivy, BeeWare, официальная tier-3-поддержка iOS/Android с 3.13), фактически — маргинальна.
  • Рефакторинг больших кодовых баз без типов. Динамика мстит на 100 тыс. строк. Лечится строгим mypy с первого дня — и это не опция, а требование (https://courses.digitable.life/post/python/07-typing/).

Куда Python тащить не надо: ядро торгового или игрового движка, драйверы, прошивки с жёстким реальным временем, CLI-утилиты, где важен старт за 5 мс (интерпретатор стартует 20–50 мс), библиотеки, которые должны потреблять чужие экосистемы (JVM, .NET). Для таких задач посмотрите на https://courses.digitable.life/post/golang/00-overview/ или https://courses.digitable.life/post/csharp/00-overview/.

Экосистема: что на чём стоит

Слои экосистемы Python: от реализации языка до инструментария

Эта картинка объясняет главный производственный приём Python: проблема производительности решается спуском на слой ниже. Медленный цикл на pandas → векторная операция numpy → при необходимости расширение на Cython или Rust. Переписывать верхний слой «умнее» бесполезно.

Пара цифр о масштабе: на PyPI более 600 тысяч пакетов, и это одновременно сила и риск — вопрос доверия к зависимостям мы разберём в https://courses.digitable.life/post/python/09-modules-and-packaging/ и https://courses.digitable.life/post/python/17-deploy-and-resources/.

Инструментальный слой за последние годы пережил смену поколений: pip + virtualenv + flake8 + black + isort во многих командах заменились на uv и ruff — оба написаны на Rust и быстрее предшественников на порядки. Это разберём сразу в следующей статье.

Версии: что живо, что мертво, куда всё идёт

Практические правила на 2026 год:

  • Новый проект начинайте на последней стабильной версии (3.14) либо на предыдущей (3.13), если ключевые зависимости ещё не собрали колёса.
  • Версии живут пять лет: примерно два года багфиксов и три года security-фиксов (PEP 602). Актуальный статус — devguide.python.org/versions.
  • Python 2 мёртв. Если вам достался код на нём — это задача миграции, а не разработки.
  • Free-threading (сборка без GIL) — самое серьёзное изменение рантайма за 20 лет, но переход займёт годы: нужна пересборка всех C-расширений. Планируйте архитектуру, исходя из наличия GIL, и радуйтесь, когда его не будет.

Конкурентность: короткая версия ответа

Вопрос «а как в Python с многопоточностью» возникает у всех сразу, поэтому дадим карту заранее. Полный разбор — в https://courses.digitable.life/post/python/11-concurrency/.

Что за нагрузка Инструмент Почему
Тысячи сетевых запросов asyncio Один поток, ожидание не блокирует; масштаб до десятков тысяч соединений
Десятки блокирующих вызовов (файлы, legacy-драйверы БД) threading / ThreadPoolExecutor GIL отпускается на I/O, потоки реально помогают
Тяжёлые вычисления на всех ядрах multiprocessing / ProcessPoolExecutor Обход GIL через отдельные процессы, ценой сериализации данных
Матрицы, массивы, ML numpy / PyTorch Вычисления уходят в C/BLAS, GIL отпускается, потоки внутри библиотеки
Веб-сервер несколько воркеров процессов + async внутри Комбинация обоих подходов

Ключевая мысль: GIL мешает только параллельному исполнению байт-кода. На I/O он не мешает вообще, на нативных вычислениях — почти не мешает. Большинство «медленно из-за GIL» на практике оказывается «медленно, потому что цикл на чистом Python».

Дорожная карта трека

Статьи выстроены лестницей — каждая опирается на предыдущие. Если вы опытный инженер из другого языка, всё равно не пропускайте 02 и 06: именно там прячется специфика, на которой спотыкаются сеньоры.

  1. Установка и инструментарий — версии и pyenv, venv, pip против uv и poetry, ruff, mypy, pre-commit, воспроизводимое окружение.
  2. Модель данных — объекты, ссылки, изменяемость, хешируемость, __eq__/__hash__, dunder-методы, подсчёт ссылок и сборка мусора.
  3. Коллекции — устройство list, dict, set, tuple, сложность операций, collections и heapq, выбор структуры под задачу.
  4. Функции и области видимости — LEGB, аргументы всех видов, замыкания и ячейки, декораторы, functools, частичное применение.
  5. ООП в Python — классы и атрибуты, MRO и C3-линеаризация, super(), дескрипторы, property, __slots__, dataclasses, метаклассы.
  6. Идиоматичный Python — итераторы и генераторы, ленивые пайплайны, yield from, контекстные менеджеры, comprehensions, itertools.
  7. Аннотации типов — mypy в строгом режиме, Protocol, дженерики PEP 695, TypedDict, Literal, Self, типизация чужого кода.
  8. Исключения — иерархия, свои классы ошибок, EAFP, contextlib.suppress, ExceptionGroup, цепочки, ретраи.
  9. Модули и пакетирование — механика импортов, циклические зависимости, pyproject.toml, wheels, публикация на PyPI.
  10. Стандартная библиотека — карта модулей, которые экономят зависимости: pathlib, datetime, json, sqlite3, logging, subprocess.
  11. Конкурентность — GIL изнутри, threading, multiprocessing, asyncio и event loop, структурная конкурентность, типичные дедлоки.
  12. Тестирование — pytest, фикстуры и их области, параметризация, моки без боли, property-based через Hypothesis, покрытие (см. также https://courses.digitable.life/post/testing/00-overview/).
  13. Производительность — профилирование по-настоящему (cProfile, py-spy, memray), алгоритмы против микрооптимизаций, Cython, Rust, PyPy.
  14. Работа с данными — numpy и векторизация, pandas и его ловушки, polars, Parquet и Arrow, память и типы колонок.
  15. Веб и API — FastAPI и Pydantic, Django и ORM, WSGI против ASGI, валидация, аутентификация, фоновые задачи.
  16. Продакшн-архитектура — слои и порты, внедрение зависимостей без фреймворка, конфигурация, структурное логирование.
  17. Деплой и ресурсы — Docker и multi-stage, healthchecks, OpenTelemetry, безопасность зависимостей, CI/CD и курированный список источников.

Сквозной пример трека

Чтобы теория не висела в воздухе, через статьи проходит один сервис — агрегатор событий: он принимает поток событий по HTTP, валидирует, складывает в хранилище и отдаёт агрегаты. Мы будем возвращаться к нему в разных разрезах:

  • в «Модели данных» — как представить событие, чтобы его можно было класть в set и сравнивать;
  • в «Коллекциях» — какую структуру взять под окно агрегации;
  • в «Идиоматике» — как построить ленивый пайплайн разбора файла на 20 ГБ;
  • в «Типах» — как описать контракт хранилища через Protocol и подменять реализацию;
  • в «Конкурентности» — как читать сотни источников без потоков;
  • в «Тестировании» — как покрыть его юнитами, интеграцией и property-based тестами;
  • в «Архитектуре» и «Деплое» — как разложить по слоям, собрать образ и наблюдать в проде.

Как учиться, чтобы уметь применять

  • Держите открытый REPL. Это главное преимущество Python перед компилируемыми языками: гипотеза проверяется за 5 секунд. python -i script.py бросает вас в интерактив с уже загруженным состоянием.
  • Читайте исходники стандартной библиотеки. Они на Python и лежат прямо у вас: python -c "import dataclasses, inspect; print(inspect.getsourcefile(dataclasses))". Код dataclasses, enum, contextlib, functools — образец идиоматики.
  • Смотрите под капот. dis, sys.getsizeof, id, gc.get_referrers, timeit — не экзотика, а повседневные инструменты для проверки «а как это на самом деле».
  • Включайте строгие инструменты с первого дня. ruff check, mypy --strict, pytest -W error. Динамический язык требует внешней дисциплины — пусть её обеспечивают машины, а не сила воли.
  • Читайте PEP. peps.python.org — это не бюрократия, а лучшая документация «почему так»: каждый PEP содержит мотивацию, отвергнутые альтернативы и обоснование.
  • Не читайте случайные ответы со Stack Overflow пятилетней давности. Python быстро меняется: %-форматирование → .format() → f-строки; os.pathpathlib; setup.pypyproject.toml. Всегда сверяйтесь с текущей документацией.

Что вы будете уметь в конце

  • Объяснять поведение любого куска Python-кода через модель данных, а не через магию.
  • Проектировать API классов через протоколы и писать код, который естественно встраивается в язык.
  • Держать строгую типизацию в проекте на сотни тысяч строк и рефакторить без страха.
  • Осознанно выбирать между asyncio, потоками и процессами, понимая, что делает GIL.
  • Находить настоящее узкое место профилировщиком и ускорять код в десятки раз.
  • Собирать, тестировать, паковать и деплоить сервис, за которым можно наблюдать в проде.

Источники, к которым стоит возвращаться

  • docs.python.org — официальная документация; отдельно Language Reference как описание семантики.
  • peps.python.org — все PEP: мотивация и обоснование решений.
  • devguide.python.org — как устроен сам CPython.
  • Лучано Рамальо, «Fluent Python», 2-е издание — лучшая книга о модели данных и идиоматике (оф. страница).
  • Дэвид Бизли, Брайан Джонс, «Python Cookbook», 3-е издание — рецепты с объяснениями; курсы и материалы Бизли о GIL и генераторах.
  • Бретт Слаткин, «Effective Python», 2-е издание — 90 конкретных правил (effectivepython.com).
  • Anthony Shaw, «CPython Internals» — устройство интерпретатора изнутри (realpython.com/products/cpython-internals-book).
  • Real Python — качественные разборы прикладных тем.
  • Блог Ned Batchelder и его классический доклад «Facts and Myths about Python names and values».

Что дальше

Установка и инструментарий: версии, venv, pip, uv, poetry, линтеры — соберём рабочее окружение так, как это делают в 2026 году: управление версиями интерпретатора, изолированные окружения, воспроизводимые зависимости, ruff и mypy в pre-commit. Без этого фундамента всё остальное превращается в «у меня на машине работало».

Нашли неточность? Выделите фрагмент текста — рядом появится жучок.

Нужен разбор именно вашей ситуации?

Статья описывает общий случай. Если у вас частный — можно разобрать его отдельно, платно. А если не хватает целого материала, предложите тему: её оплачивают вскладчину, и она выходит открытой для всех.

Доска запросов