Про книгу Энтони Шоу «Внутри CPython»
После того, как более-менее освоишь какой-либо инструмент, которым постоянно пользуешься, полезно заглянуть в его «внутренности», чтобы его работа не воспринималась как магия, которая каким-то неведомым образом что-то делает. Поэтому, когда вышла книга Энтони Шоу «Внутри CPython», я ее сразу заказал. На днях я ее дочитал и расскажу о ней в этом посте.
Сразу определимся с терминологией, чтобы было ясно, о чем книга. CPython (не путайте с Cython) — это эталонная реализация Python, которая написана на языке C. Собственно, это и есть тот самый интерпретатор Python, которым пользуются большинство питонистов. Как вы, наверное, знаете, есть и другие интерпретаторы Python, написанные на других языках. Например, PyPy (интерпретатор, написанный на Python), IronPython (реализация Python под платформу .NET), Jython (реализация на Java). В данной же книге речь идет о всем знакомом интерпретаторе, а не о каком-то экзотическом (да простят меня пользователи перечисленных выше реализаций).
Сразу скажу, что книга оставила у меня неоднозначное впечатление. Наверное, я ожидал от нее чуть более высокоуровневого описания работы Python, надеялся, что больше будет написано про байт-код и его ассемблерные команды. В реальности книга представляет собой обзорную экскурсию по исходникам интерпретатора Python. На самом деле это тоже любопытно, но эти знания более удалены от практики применения Python. Эту книгу можно посоветовать тем, кто хочет начать участвовать в разработке CPython. К сожалению, она уже начала устаревать. В ней речь идет о Python 3.9, и когда я ее начал читать, то решил, что я буду смотреть в исходники Python 3.11, но там уже некоторых файлов не стало, а какие-то были переименованы. Особенно это касается частей кода, связанных с парсером. О некоторых подобных изменениях автор предупреждает, говоря о том, что парсер был переписан, но в Python 3.9 можно было найти обе версии, а в 3.11 осталась только новая. С другой стороны, это был тоже любопытный квест, искать куски кода, если указанного файла нет.
Читать эту книгу лучше, сидя за компьютером, где скачаны исходники, постоянно в них заглядывая или хотя бы находя файлы, которые упоминаются в книге. Именно поэтому чтение этой книги у меня затянулось на большее время, чем я ожидал — я обычно читаю, лежа на диване, чтобы отдохнуть от монитора, или в транспорте.
Давайте теперь пробежимся по содержанию книги, чтобы понять, о чем конкретно там написано.
Начинается все с общего обзора исходников, в какой папке что лежит. Где-то десяток страниц посвящено настройке разных редакторов кода (Visual Studio Code, CLion, Vim). Честно говоря, не знаю, зачем это. Наверное, если вы полезли в исходники Python, то у вас уже есть настроенный любимый редактор. К тому же писать что-то о vim всего на 4-х страницах — это по меньшей мере странно. Ну ладно, пусть будет.
Затем начинается глава о том, как компилировать исходники CPython в разных операционных системах: Windows, Linux, MacOS. Написано, какие зависимости должны быть установлены, какие флаги компиляции существуют и т.п. Это уже действительно полезный материал.
После этого идет глава о том, как и в каких файлах исходниках описывается грамматика языка Python. На протяжении всей книги в качестве сквозного примера автор будет добавлять в интерпретатор новый оператор «~=» — «приблизительно равно», который будет вести себя по-разному для разных встроенных типов данных (для типа float этот оператор будет производить сравнение с небольшим допуском, для строк это будет равносильно сравнению без учета регистра).
Отдельная небольшая глава посвящена тому, каким образом можно конфигурировать интерпретатор (переменные окружения, параметры командной строки), а также тому, как он поступает, когда ему на вход поступает выполняемая программа разными способами в командной строке (непосредственная передача имени файла, строки с текстом программы с использованием параметра «-с», имени модуля с использованием параметра «-m», передача программы через pipe на stdin интерпретатора). В основном здесь рассказывается о том, какие структуры используются для начальной установки конфигурации, а также где искать в исходниках функции, которые вызываются при том или ином способе запуска интерпретатора (передачи ему скрипта). Эта глава — начало цепочки глав, в которых автор последовательно проводит нас сквозь последовательность операций, которые осуществляются с момента запуска интерпретатора и до вывода результата работы скрипта, который был передан на вход.
После этого автор рассказывает про то, как работают парсер и лексический анализатор интерпретатора Python. На данный момент, именно эта глава больше всего устарела. Причем автор честно пишет, что эта часть интерпретатора подверглась переписыванию, но в Python 3.9 были еще и старая, и новая версии парсера. Поскольку только алгоритмам парсинга и построению синтаксических деревьев можно посвящать целую книгу, а автор ограничен всего лишь 20-ю страницами одной главы, то не стоит надеяться, что после этой главы вы полностью разберетесь в этом процессе. Самое интересное здесь — это общая идеология и ссылки на инструмент instaviz, который визуализирует построенные синтаксические деревья.
После главы про парсер начинается глава про компилятор в байт-код, который использует полученное на предыдущем шаге синтаксическое дерево. Здесь автор аккуратно разделяет непосредственно компилятор и ассемблер. Компилятор обходит синтаксическое дерево и строит граф потока управления, представляющий собой логическую последовательность выполнения. Ассемблер затем эту последовательность преобразует в байт-код. Вообще было бы интересно почитать про ассемблерные команды байт-кода (программирование на ассемблере под Python), но, к сожалению, в этой книге лишь вскользь упоминаются только несколько таких команд.
Следующая глава рассказывает о том, как выполняется байт-код, построенный на предыдущем шаге ассемблером. Здесь говорится о так называемом цикле вычислений, о том, как настраивается главный поток (thread), в котором выполняется код, как формируется кадр стека, который создается для вызова каждой функции, рассказывается о передаче именованных и не именованных параметров в функцию.
Следующая глава на мой взгляд одна из самых интересных — она посвящена работе с памятью. В ней коротко (на 40 страницах) рассказывается о том, как интерпретатор выделяет и освобождает память, как происходит подсчет ссылок и как работает сборщик мусора. Если про выделение памяти в этой главе написано достаточно подробно, то про сборку мусора автор пишет совсем коротко, а жаль…
Еще одна глава посвящена параллелизму и конкурентности. Опять же, это настолько обширная тема, что про нее пишут отдельные книги. Например, недавно я писал о одной из таких книг — «Asyncio и конкурентное программирование на Python». Эта глава книги у меня оставила неоднозначные впечатления как раз из-за того, что автор попытался в нее впихнуть сразу много разнородных тем. Например, сюда вошла тема о создании процессов в разных операционных системах (Linux / Windows), рассказывает о различиях между порождением и ответвлением процессов, о межпроцессном взаимодействии. Затем автор переходит к многопоточности и GIL, а в завершение главы — к асинхронному программированию.
Еще одна глава посвящена тому, как реализованы встроенные типы: классы object, type, словарь, bool, целые числа, строки (рассказывается о кодировках).
И в последних главах автор пишет о тестировании, измерении производительности и отладке. Если главы про запуск тестов и бенчмарков, хоть и совсем короткие, но полезные, если вы собираетесь править код Python, то глава про отладчики, скажем так, приклеена рядом синей изолентой. В ней в основном автор перечисляет наиболее известные отладчики, включая GDB, а также встроенные в Visual Studio и CLion, и показывает как их запускать и ставить точки останова. Мне снова кажется, что это все-таки не тот уровень для тех, кто уже осмелился лезть в исходники Python.
А заканчивается книга напутствиями относительно того, как влиться в ряды коммитеров в репозиторий Python, с чего начать новичкам, как искать задачи под свой уровень.
В целом у меня от книги осталось странное впечатление. С одной стороны, подобные книги именно про исходные коды Python мне не попадались, и это здорово, что кто-то решил рассказать хоть что-то на эту тему. Если ваша цель — начать контрибьютить в исходники Python, то для начала книга вполне сойдет. Я ожидал от нее немного другого, чего-то, что было бы полезно разработчику на Python для понимания работы интерпретатора, что можно было бы использовать в разработке своего софта. Например, хотелось бы прочитать про разработку модулей на C, про ассемблер для байт-кода. Интересные моменты такого чуть более высокого уровня в книге есть, но их мало и они как бы проскакивают вскользь. Все-таки основная цель книги — это показать, где что лежит в исходниках интерпретатора, не особо вдаваясь в подробности алгоритмов.
Меня удивил отзыв на эту книгу, где рецензент(ша) переживает по поводу того, что ей такая книга не попадалась, когда она только изучала Python. Вот уж точно не согласен, что учеников и студентов стоит грузить такими низкоуровневыми вещами во время изучения языка. Вот для тех, кто себя уже уверенно чувствует в среде Python — вполне можно, особенно, если до этого им уже прочитали курс лекций по работе компиляторов.
Что касается перевода, то у меня есть к нему некоторые претензии, некоторые фразы напоминают автоматический перевод, но в целом все написано понятно, может быть не всегда по-русски. Я обычно не пишу про качество самой книги как физического объекта, но тут не могу не пожаловаться на то, что как только я начал читать книгу, из нее тот же начали выпадать листы. Когда я об этом пожаловался у себя в телеграм-канале (кстати, подписывайтесь), то мне кинули ссылку на статью на Хабре, где народ жаловался на такие же проблемы с этой книжкой. К счастью, «листопад» у меня закончился достаточно быстро, выпала только пара… кажется в переплетном деле, это правильно называется тетрадей.
Итого, не буду говорить, что книгу нужно прочитать обязательно всем, но если вас она все-таки заинтересовала, то поторопитесь, пока она не устарела совсем, ведь разработчики Python не сидят без дела и переписывают код, делая эту книгу все менее актуальной.
Список обзоров остальных прочитанных мной книг, можете найти на этой странице.
PS. Вы можете подписаться на новости сайта через RSS, Группу Вконтакте или Канал в Telegram.
Leave a comment