Двадцать одна глава о том, почему язык устроен именно так. Не справочник и не список подводных камней: девять принятых когда-то решений и всё, что из них следует, — чтобы ответы можно было выводить, а не вспоминать.
Внутри главы три уровня. L1 — законченный ответ: механизм, причина, компромисс; его достаточно, чтобы принимать верные решения в коде. L2 — структура в памяти и цифры. L3 — конкретное место в исходниках CPython. L1 никогда не отсылает вниз без причины: если он что-то опускает, то говорит, при каких условиях это начинает иметь значение.
Главы связаны выводом, и на первом чтении порядок не произволен: часть следствий нельзя получить, не приняв предыдущий корень. Ниже корни идут именно в этом порядке, а не по номерам.
R1 первым, потому что без него не выводится ничего. R3 сразу за ним: время жизни объекта — прямое следствие того, что значение это объект, и оттуда же берётся GIL. R6 поздно, потому что требует и R1, и R3. R9 последним: это не механизм, а рамка, в которой принимались все остальные решения, и оценить её можно только зная их.
В тексте у неочевидных утверждений стоит значок. Различать эти три вещи — отдельный навык, и он важнее любого отдельно взятого факта.
Единая объектная модель без примитивов: одно правило вместо двух — и заголовок у каждого числа как цена за это.
+= и разница is и ==.готовоinsert(0), почему миллион чисел весит 36 МБ.готовоСчётчик даёт детерминированное разрушение — и он же вынуждает GIL: за удобный with заплачено глобальным локом.
with — и отсюда же GIL.готово__del__, отключение сборщика и почему RSS не мера утечки.готовоПоиск в момент обращения — источник всей выразительности языка и причина двадцати лет медленного доступа к атрибуту.
obj.x насквозьПроцедура из четырёх шагов: дескрипторы, property, явный self, __slots__, инлайн-кеши.готово__new__ против __init__, C3-линеаризация, что на самом деле делает super().готовоtype как фабрика классов — и почему в прикладном коде почти всегда хватает __init_subclass__.готовоwraps, lru_cache на методе как тихая утечка.готовоИнтерфейс — не декларация, а набор дандеров; проверяемые контракты приделывали к языку дважды и оба раза сильно позже.
len() функция, ABC в 2007-м и Protocol в 2017-м.готово__exit__ подавлять исключение, return в finally, две цепочки причин.готовоОдин протокол, из которого выросли генераторы, а из генераторов — вся асинхронность.
yield fromОдноразовость итератора, приостановленный кадр и почему цикл не заменяет yield from.готовоTaskGroup против gather.готовоМодуль исполняется один раз и живёт весь процесс: отсюда циклические импорты и половина странностей в тестах.
Граница, на которой стоит весь научный стек, — и она же не даёт просто взять и убрать GIL.
memoryview, почему numpy параллелится потоками, а цикл нет.готовоТипы принципиально необязательны: доказательств нет, зато миграция огромной кодовой базы возможна.
TYPE_CHECKING, зачем нужен отдельный слой валидации.готовоПосле Python 3 ломать нельзя. Деталь реализации становится обещанием ровно тогда, когда на неё оперлось слишком много кода.
Отдельных глав нет: это не механизм, а рамка. Живёт эссе на странице корня.
Пять тем, каждая из которых опирается сразу на несколько корней и потому идёт после них. Последние две — конвейер целиком: их можно читать и первыми, как карту машины, и последними, как сведение всего остального.
python script.py до code object: старт интерпретатора, токенайзер, парсер, таблица символов, компилятор, .pyc.готовоТри страницы поверх глав. Читать их имеет смысл после первого прохода — по отдельности они выглядят как справочники, а работают как проверка того, что корни сошлись.
Слой «прочувствовать»: механизм, описанный словами, и механизм, который покрутил руками, оседают по-разному. Три интерактивные страницы, работают с телефона, ничего не грузят из сети.