Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Внутри CPython гид по интерпретатору Python.pdf
Скачиваний:
6
Добавлен:
07.04.2024
Размер:
8.59 Mб
Скачать

Стандартная библиотека

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