Глава 12. Стандартная библиотека
Python всегда поставляется вместе с батарейками. Это означает, что стандартный дистрибутив Python содержит библиотеки для работы с файлами, потоками, вебсайтами, музыкой, клавиатурой, экранами, текстом и целым диапазоном утилит.
Некоторые из поставляемых совместно с CPython батареек подобны батарейкам АА и полезны практически при любой ситуации. В качестве примеров
можно привести модули collections
и sys
. Но некоторые из них
слегка менее известны, превращая их в некое подобие батареек от наручных часов: вы никогда не знаете наперёд когда они вам понадобятся.
Имеются два типа модулей в стандартной библиотеке CPython:
-
Те, кторые написаны на чистом Python и которые предоставляют утилиты
-
Те, которые написаны на C с обёрткой из Python
В данной главе мы изучим оба этих типа.
Все те модули, которые написаны на чистом Python, располагаются в каталоге Lib
исходного кода.
Некоторые более старшие модули обладают подчинёнными модулями в подчинённых папках, такие как модуль email
.
Некий простой модуль, с которым вы могли не сталкиваться ранее это модуль colorsys
. Он обладает
сотней строк кода Python и содержит некие функции утилит для преобразования цветовых шкал.
Когда вы устанавливаете дистрибутив Python из исходного кода, модули стандартной библиотеки копируются из папки
Lib
в папку своего дистрибутива. Эта папка всегда выступает частью вашего пути при запуске Python,
поэтому вы способны выполнять import
таких модулей не беспокоясь относительно их местоположения.
Например, вот как импортировать и применять 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: Hue, Luminance, Saturation
# H: position in the spectrum
# L: color lightness
# S: color saturation
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, хорошо разложенном и несложном для понимания.
Вы даже можете заметить улучшения или ошибки в модулях стандартной библиотеки. Если это именно так, вы способны делать изменения и вносить их в общий дистрибутив Python. Мы рассмотрим это в самом конце данной книги.
Все остающиеся модули написаны на C или на комбинации Pyton и C. Их исходный код расположен в Lib
для компонентов Pyton и в Modules
для компонентов C. Имеются два исключения:
-
Модуль
sys
находится вPython/sysmodule.c
-
А модуль
__builtins__
обнаруживается вPython/bltinmodule.c
Поскольку этот модуль sys
настолько специфичен для своего интерпретатора и внутреннего устройства
CPython, он обнаруживается в самом каталоге Python
. Он также помечается в качестве
"подробности реализации" CPythonи не находится в прочих дистрибутивах.
Python будет import * from __builtins__
при конкретизации интерпретатора, поэтому все такие встроенные функции,
как print()
, chr()
, format()
и тому подобные обнаруживаются внутри Python/bltinmodule.c
.
Встроенная функция print()
вероятно была самой первой изученной вами для применения в Python. Итак,
что в точности происходит когда вы набираете print("Hello, World")
?
Вот разбивка:
-
Наш компилятор преобразовывает полученный аргумент
"Hello, World"
из строковой константы вPyUnicodeObject
. -
builtin_print() исполняется с одним аргументом и
NULL kwnames
. -
Значение переменной
file
устанавливается вPyId_stdout
, системный обработчикstdout
. -
Все аргументы отправляются в
file
. -
В
file
отправляется разрыв строки (\n
).
Вот как это работает, строка 1828 Python/bltinmodule.c
:
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, выставляющем функции операционной системы. Поскольку исходный код CPyton необходимо компилировать в to macOS, Windows, Linux и прочих основанных на *nix операционных системах, существуют некие особые случаи.
Хорошим примером выступает модуль time
. Тот способ, коим Windows удерживает и сохраняет время в своей
операционной системе фундаментально отличается от Linux и macOS. Это одна из причин, по которой значение точности часов
отличается в операционных системах.
В 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 являются модули построения потоков. Поскольку операционные системы ведут себя по разному, сам исходный код CPython реализует в точности то поведение, которое подходит наилучшим образом и выставляет его применяя совместимый, абстрагированный API.