- •Об авторе
- •О группе редакторов
- •Предисловие
- •Введение
- •Как использовать эту книгу
- •Загрузка исходного кода CPython
- •Что в исходном коде?
- •Настройка среды разработки
- •IDE или редактор?
- •Настройка Visual Studio
- •Настройка Visual Studio Code
- •Настройка Vim
- •Выводы
- •Компиляция CPython
- •Компиляция CPython на macOS
- •Компиляция CPython на Linux
- •Установка специализированной версии
- •Знакомство с Make
- •Make-цели CPython
- •Компиляция CPython на Windows
- •Профильная оптимизация
- •Выводы
- •Грамматика и язык Python
- •Спецификация языка Python
- •Генератор парсеров
- •Повторное генерирование грамматики
- •Выводы
- •Конфигурация и ввод
- •Конфигурация состояния
- •Структура данных конфигурации среды выполнения
- •Конфигурация сборки
- •Сборка модуля из входных данных
- •Выводы
- •Генерирование конкретного синтаксического дерева
- •Парсер/токенизатор CPython
- •Абстрактные синтаксические деревья
- •Важные термины
- •Пример: добавление оператора «почти равно»
- •Выводы
- •Компилятор
- •Исходные файлы
- •Важные термины
- •Создание экземпляра компилятора
- •Флаги будущей функциональности и флаги компилятора
- •Таблицы символических имен
- •Основная компиляция
- •Ассемблер
- •Создание объекта кода
- •Использование Instaviz для вывода объекта кода
- •Пример: реализация оператора «почти равно»
- •Выводы
- •Цикл вычисления
- •Исходные файлы
- •Важные термины
- •Построение состояния потока
- •Построение объектов кадров
- •Выполнение кадра
- •Стек значений
- •Пример: добавление элемента в список
- •Выводы
- •Управление памятью
- •Выделение памяти в C
- •Проектирование системы управления памятью Python
- •Аллокаторы памяти CPython
- •Область выделения объектной памяти и PyMem
- •Область выделения сырой памяти
- •Нестандартные области выделения памяти
- •Санитайзеры выделенной памяти
- •Арена памяти PyArena
- •Подсчет ссылок
- •Сборка мусора
- •Выводы
- •Параллелизм и конкурентность
- •Модели параллелизма и конкурентности
- •Структура процесса
- •Многопроцессорный параллелизм
- •Многопоточность
- •Асинхронное программирование
- •Генераторы
- •Сопрограммы
- •Асинхронные генераторы
- •Субинтерпретаторы
- •Выводы
- •Объекты и типы
- •Примеры этой главы
- •Встроенные типы
- •Типы объектов
- •Тип type
- •Типы bool и long
- •Тип строки Юникода
- •Словари
- •Выводы
- •Стандартная библиотека
- •Модули Python
- •Модули Python и C
- •Набор тестов
- •Запуск набора тестов в Windows
- •Запуск набора тестов в Linux или macOS
- •Флаги тестирования
- •Запуск конкретных тестов
- •Модули тестирования
- •Вспомогательные средства тестирования
- •Выводы
- •Отладка
- •Обработчик сбоев
- •Компиляция поддержки отладки
- •LLDB для macOS
- •Отладчик Visual Studio
- •Отладчик CLion
- •Выводы
- •Бенчмаркинг, профилирование и трассировка
- •Использование timeit для микробенчмарка
- •Использование набора тестов производительности Python
- •Профилирование кода Python с использованием cProfile
- •Выводы
- •Что дальше?
- •Создание расширений C для CPython
- •Улучшение приложений Python
- •Участие в проекте CPython
- •Дальнейшее обучение
- •Препроцессор C
- •Базовый синтаксис C
- •Выводы
- •Благодарности
Стандартная библиотека
Python всегда поставлялся с «батарейками в комплекте». Это означает, что стандартный дистрибутив CPython содержит библиотеки для работы с файлами, потоками, сетями, веб-сайтами, музыкой, клавиатурами, экранами, текстом и широким спектром утилит.
Некоторые «батарейки», поставляемые с CPython, можно сравнить с батарейками AA, которые подойдут почти для любого случая, как, например, модуль collections и модуль sys. Но другие больше похожи на маленькие батарейки для часов: никогда не знаешь, когда они могут понадобиться.
Стандартная библиотека CPython включает два типа модулей:
1.Модули, написанные на чистом Python.
2.Модули, написанные на C с обертками Python.
Вэтой главе будут рассмотрены оба типа.
МОДУЛИ PYTHON
Все модули, написанные на чистом Python, находятся в каталоге Lib исходного кода. Некоторые крупные модули могут содержать подмодули в подкаталогах (например, модуль email).
Например, существует такой простой модуль, как colorsys. Возможно, вы с ним еще не сталкивались. Он содержит всего сто строк Python-кода и служебные функции для преобразования цветовых шкал.
При установке дистрибутива Python из исходного кода модули стандартной библиотеки копируются из папки Lib в папку дистрибутива. Эта папка всегда
Книги для программистов: https://t.me/booksforits
Модули Python 289
является частью пути при запуске Python, что позволяет вам импортировать модули, не беспокоясь о том, где они располагаются.
Импортирование и использование colorsys может выглядеть так:
>>>import colorsys
>>>colorsys
<module 'colorsys' from '/usr/shared/lib/python3.7/colorsys.py'>
>>> colorsys.rgb_to_hls(255,0,0) (0.0, 127.5, -1.007905138339921)
Исходный код rgb_to_hls() находится в Lib colorsys.py:
#HLS: тон, яркость, насыщенность
#H: позиция в спектре
#L: яркость цвета
#S: насыщенность цвета
def rgb_to_hls(r, g, b): maxc = max(r, g, b) minc = min(r, g, b)
# XXX Can optimize (maxc+minc) and (maxc-minc) l = (minc+maxc)/2.0
if minc == maxc: return 0.0, l, 0.0
if l <= 0.5:
s = (maxc-minc) / (maxc+minc) else:
s = (maxc-minc) / (2.0-maxc-minc) rc = (maxc-r) / (maxc-minc)
gc = (maxc-g) / (maxc-minc) bc = (maxc-b) / (maxc-minc) if r == maxc:
h = bc-gc elif g == maxc:
h = 2.0+rc-bc else:
h = 4.0+gc-rc h = (h/6.0) % 1.0 return h, l, s
В этой функции нет ничего особенного — вполне стандартный код Python. Так можно сказать обо всех модулях стандартной библиотеки, написанных на чистом Python. Все они содержат обычный код Python, хорошо структурированы и не особенно сложны для понимания.
Книги для программистов: https://t.me/booksforits
290 Стандартная библиотека
Возможно, среди них вы даже найдете те, которые можно улучшить, или заметите ошибки. В таком случае можно внести изменения и включить их в дистрибутив Python. Рассмотрим эту возможность ближе к концу книги.
МОДУЛИ PYTHON И C
Остальные модули написаны на C или сочетают Python и C. Для компонента Python исходный код хранится в каталоге Lib, а для С — в каталоге Modules. Существуют два исключения:
1.Модуль sys находится в файле Python sysmodule.c.
2.Модуль __builtins__ находится в файле Python bltinmodule.c.
Так как модуль sys тесно связан с интерпретатором и внутренними механизмами CPython, он хранится в каталоге Python. Он также помечен как «деталь реализации» CPython и отсутствует в других дистрибутивах.
Python выполняет import * from __builtins__ при создании экземпляра интерпретатора, так что все встроенные функции, такие как print(), chr(), format() и т. д., — находятся в Python bltinmodule.c.
Вероятно, ваше изучение Python началось именно со встроенной функции print().
Так что же происходит, когда вы вызываете print("Hello, World")?
Общая схема выглядит так:
1.Компилятор преобразует аргумент "Hello, World" из строковой константы в PyUnicodeObject.
2.builtin_print() выполняется с одним аргументом и NULL kwnames.
3.Переменной file присваивается PyId_stdout, системный обработчик стандартного вывода stdout.
4.Каждый аргумент передается file.
5.В file отправляется символ новой строки (\n).
Вот как это работает:
Книги для программистов: https://t.me/booksforits
Модули Python и C 291
Python bltinmodule.c, строка 1828
static PyObject *
builtin_print(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
...
if (file == NULL || file == Py_None) {
file = _PySys_GetObjectId(&PyId_stdout);
...
}
...
for (i = 0; i < nargs; i++) { if (i > 0) {
if (sep == NULL)
err = PyFile_WriteString(" ", file);
else
err = PyFile_WriteObject(sep, file, Py_PRINT_RAW);
if (err)
return NULL;
}
err = PyFile_WriteObject(args[i], file, Py_PRINT_RAW); if (err)
return NULL;
}
if (end == NULL)
err = PyFile_WriteString("\n", file);
else
err = PyFile_WriteObject(end, file, Py_PRINT_RAW);
...
Py_RETURN_NONE;
}
Содержимое некоторых модулей, написанных на C, открывает доступ к функциям операционной системы. Так как исходный код CPython должен компилироваться для macOS, Windows, Linux и других операционных систем семейства *nix, существуют некоторые особые случаи.
Хорошим примером служит модуль time. Способ хранения времени в операционной системе Windows принципиально отличается от Linux и macOS. Это одна из причин, по которым точность функций часов зависит от операционной системы1.
1 https://docs.python.org/3/library/time.html#time.clock_gettime_ns.
Книги для программистов: https://t.me/booksforits
292 Стандартная библиотека
В файле Modules timemodule.c функции времени ОС для систем семейства Unix импортируются из <sys/times.h>:
#ifdef HAVE_SYS_TIMES_H
#include <sys/times.h> #endif
...
#ifdef MS_WINDOWS
#define WIN32_LEAN_AND_MEAN #include <windows.h> #include "pythread.h" #endif /* MS_WINDOWS */
...
Далее в файле функция time_process_time_ns() объявляется как обертка для _PyTime_GetProcessTimeWithInfo():
static PyObject *
time_process_time_ns(PyObject *self, PyObject *unused)
{
_PyTime_t t;
if (_PyTime_GetProcessTimeWithInfo(&t, NULL) < 0) { return NULL;
}
return _PyTime_AsNanosecondsObject(t);
}
_PyTime_GetProcessTimeWithInfo() реализуется в исходном коде несколькими разными способами, но лишь некоторые части компилируются в двоичный файл для модуля в зависимости от операционной системы. В системах Windows вызывается GetProcessTimes(), а в системах Unix — clock_gettime().
Существуют и другие модули, имеющие несколько реализаций для одного API: модуль threading1, модуль файловой системы и сетевые модули. Так как операционные системы обладают разным поведением, исходный код CPython реализует одно и то же поведение, настолько хорошо, насколько это возможно, и предоставляет целостный абстрагированный API.
1 https://realpython.com/intro-to-python-threading/.
Книги для программистов: https://t.me/booksforits