Канон

Канон Python

Двадцать одна глава о том, почему язык устроен именно так. Не справочник и не список подводных камней: девять принятых когда-то решений и всё, что из них следует, — чтобы ответы можно было выводить, а не вспоминать.

1Как читать

КартаТолько верхний слой всех глав. Пара вечеров с телефона — и структура языка на месте.
ВопросПришёл с конкретным «почему оно так себя ведёт» — берёшь одну главу целиком.
ВглубьОдин корень насквозь: байты, исходники CPython, замеры на своей машине.

Внутри главы три уровня. L1 — законченный ответ: механизм, причина, компромисс; его достаточно, чтобы принимать верные решения в коде. L2 — структура в памяти и цифры. L3 — конкретное место в исходниках CPython. L1 никогда не отсылает вниз без причины: если он что-то опускает, то говорит, при каких условиях это начинает иметь значение.

2Порядок первого прохода

Главы связаны выводом, и на первом чтении порядок не произволен: часть следствий нельзя получить, не приняв предыдущий корень. Ниже корни идут именно в этом порядке, а не по номерам.

R1 объект и ссылка → R3 счётчик ссылок → R2 атрибут → R4 протоколы → R5 итерация → R7 импорт → R6 граница с C → R8 типы → R9 совместимость

R1 первым, потому что без него не выводится ничего. R3 сразу за ним: время жизни объекта — прямое следствие того, что значение это объект, и оттуда же берётся GIL. R6 поздно, потому что требует и R1, и R3. R9 последним: это не механизм, а рамка, в которой принимались все остальные решения, и оценить её можно только зная их.

3Шкала твёрдости

В тексте у неочевидных утверждений стоит значок. Различать эти три вещи — отдельный навык, и он важнее любого отдельно взятого факта.

🔒Гарантия языка. Зафиксировано, опирайся смело.
🔧Деталь CPython. Работает, но никто не обещал: на другой реализации или в следующем релизе может исчезнуть.
🕳Не определено. Зависит от платформы, сборки, или просто никем не зафиксировано.

4Главы

Единая объектная модель без примитивов: одно правило вместо двух — и заголовок у каждого числа как цена за это.

  1. 01Имя, объект, ссылкаОпределение, из которого выводятся mutable default, алиасинг, поведение += и разница is и ==.готово
  2. 02Числа и строки: примитивов нетПроизвольная точность, деление вниз вместо усечения, три представления строки, интернирование.готово
  3. 03КонтейнерыСписок как массив указателей, закон роста, цена insert(0), почему миллион чисел весит 36 МБ.готово

Счётчик даёт детерминированное разрушение — и он же вынуждает GIL: за удобный with заплачено глобальным локом.

  1. 09Подсчёт ссылокОбъект живёт, пока на него смотрят: отсюда работающий with — и отсюда же GIL.готово
  2. 10Циклы, сборщик и памятьПоколения, ненадёжный __del__, отключение сборщика и почему RSS не мера утечки.готово

Поиск в момент обращения — источник всей выразительности языка и причина двадцати лет медленного доступа к атрибуту.

  1. 04obj.x насквозьПроцедура из четырёх шагов: дескрипторы, property, явный self, __slots__, инлайн-кеши.готово
  2. 05dict и хешируемостьКомпактная раскладка, контракт хеша, порядок ключей как случайно принятая гарантия.готово
  3. 06Классы__new__ против __init__, C3-линеаризация, что на самом деле делает super().готово
  4. 07Метаклассыtype как фабрика классов — и почему в прикладном коде почти всегда хватает __init_subclass__.готово
  5. 08Функции, замыкания, декораторыЯчейки и позднее связывание, потеря сигнатуры без wraps, lru_cache на методе как тихая утечка.готово

Интерфейс — не декларация, а набор дандеров; проверяемые контракты приделывали к языку дважды и оба раза сильно позже.

  1. 11ПротоколыДандеры как слоты типа, почему len() функция, ABC в 2007-м и Protocol в 2017-м.готово
  2. 12Контекстные менеджеры и исключенияПраво __exit__ подавлять исключение, return в finally, две цепочки причин.готово

Один протокол, из которого выросли генераторы, а из генераторов — вся асинхронность.

  1. 13Итератор, генератор, yield fromОдноразовость итератора, приостановленный кадр и почему цикл не заменяет yield from.готово
  2. 14async/await изнутриКорутина как кадр, цикл событий, один синхронный вызов на весь сервис, TaskGroup против gather.готово

Модуль исполняется один раз и живёт весь процесс: отсюда циклические импорты и половина странностей в тестах.

  1. 17Импорт насквозьИсполнение вместо подключения, общее состояние модуля, где патчить mock, циклические импорты.готово

Граница, на которой стоит весь научный стек, — и она же не даёт просто взять и убрать GIL.

  1. 15Граница и zero-copyBuffer protocol, memoryview, почему numpy параллелится потоками, а цикл нет.готово
  2. 16Пакеты и переписываниеABI и manylinux, почему пакет не ставится, полная цена выноса кода в C или Rust.готово

Типы принципиально необязательны: доказательств нет, зато миграция огромной кодовой базы возможна.

  1. 18Типы стёртыАннотации как данные, TYPE_CHECKING, зачем нужен отдельный слой валидации.готово

После Python 3 ломать нельзя. Деталь реализации становится обещанием ровно тогда, когда на неё оперлось слишком много кода.

Отдельных глав нет: это не механизм, а рамка. Живёт эссе на странице корня.

—

Сквозные

Пять тем, каждая из которых опирается сразу на несколько корней и потому идёт после них. Последние две — конвейер целиком: их можно читать и первыми, как карту машины, и последними, как сведение всего остального.

  1. 19GILЧто защищает на самом деле, атомарность против корректности, что меняет free-threading.готово
  2. 20Конкурентность: дерево решенийПотоки, asyncio, процессы, субинтерпретаторы — по природе нагрузки и объёму передачи.готово
  3. 21ПроизводительностьПорядок рычагов от алгоритма до переписывания; почему половина советов устарела после 3.11.готово
  4. 22Из текста в байткодДевять фаз от python script.py до code object: старт интерпретатора, токенайзер, парсер, таблица символов, компилятор, .pyc.готово
  5. 23Машина исполненияФрейм, стек значений, цикл вычисления, инлайн-кеши внутри байткода, исключения без накладных расходов, завершение процесса.готово

5Сводные страницы

Три страницы поверх глав. Читать их имеет смысл после первого прохода — по отдельности они выглядят как справочники, а работают как проверка того, что корни сошлись.

СинтезДевять корней одной схемой с рёбрами взаимного влияния. У GIL нет собственного корня — он стоит на ребре. Гарантия или детальРеестр из 57 утверждений по шкале 🔒 · 🔧 · 🕳. На что можно опереться архитектурно, а что не проверять даже тестом. Что читать дальшеПервоисточники, четыре книги, доклады — и отдельно то, что читать не стоит.

6Лаборатории

Слой «прочувствовать»: механизм, описанный словами, и механизм, который покрутил руками, оседают по-разному. Три интерактивные страницы, работают с телефона, ничего не грузят из сети.

Что лежит в байтахНастоящий дамп памяти восьми объектов, разложенный по полям заголовка. Наведите на поле — подсветятся его байты. Счётчик и циклыТри сценария по шагам: где счётчика хватает, где он бессилен принципиально и как выглядит настоящая утечка. GIL во времениКто держит блокировку, кто ждёт и кто считает без неё — по трём типам нагрузки, рядом с замерами.
Чем это не является. Не учебником Python и не объяснением синтаксиса. Не списком подводных камней: ни одна ловушка не получает отдельной главы — только как следствие механизма там, где механизм разбирается. Не тренажёром к собеседованиям. И не пересказом документации: там, где официальный текст лучше, глава отправляет туда и говорит, читать его целиком или выборочно.