Вступление¶
Интерфейс прикладного программирования для Python предоставляет C и C++ программистам доступ к интерпретатору Python на различных уровнях. API также можно использовать с C++, но для краткости его обычно называют Python/C API. Есть две принципиально разные причины использования API Python/C. Первая причина — разработка модулей расширения для определенных целей; это модули C, расширяющие интерпретатор Python. Это, вероятно, наиболее распространённое использование. Вторая причина — использовать Python как компонент в более крупном приложении; данный метод обычно используется при встраивании Python в приложение.
Написание модуля расширения — это относительно хорошо понятный процесс, в котором хорошо работает подход «поваренной книги». Есть несколько инструментов, которые в некоторой степени автоматизируют данный процесс. Хотя люди встраивали Python в другие приложения с самого начала его существования, процесс встраивания Python менее прост, чем написание расширения.
Многие функции API полезны независимо от того, встраиваете ли вы Python или расширяете его; более того, большинство приложений, которые встраивают Python, также должны предоставлять собственное расширение, поэтому, вероятно, будет хорошей идеей ознакомиться с написанием расширения, прежде чем пытаться встроить Python в реальное приложение.
Стандарты кодирования¶
Если вы пишете код C для включения в CPython, вы должны следовать рекомендациям и стандартам, определённым в PEP 7. Эти правила применяются независимо от версии Python, над которой вы работаете. Соблюдение этих соглашений не является обязательным для ваших собственных сторонних модулей расширения, если вы в конечном итоге не планируете вносить их в Python.
Подключение файлов¶
Все определения функций, типов и макросов, необходимые для использования Python/C API, подключаются в ваш код следующей строкой:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
Это подразумевает подключение следующих стандартных заголовков: <stdio.h>
,
<string.h>
, <errno.h>
, <limits.h>
, <assert.h>
и <stdlib.h>
(при наличии).
Примечание
Поскольку Python может определять некоторые определения препроцессора,
которые влияют на стандартные заголовки в некоторых системах, вы должны
подключать Python.h
перед подключением любых стандартных заголовков.
Перед подключением Python.h
рекомендуется всегда определять
PY_SSIZE_T_CLEAN
. См. описание этого макроса в Анализ аргументов и сборка значений.
Все видимые пользователем имена, определённые Python.h (кроме тех, которые
определены включенными стандартными заголовками), содержат один из префиксов
Py
или _Py
. Имена, начинающиеся с _Py
, предназначены для
внутреннего использования реализацией Python и не должны использоваться
разработчиками расширений. У имена членов структуры нет зарезервированного
префикса.
Примечание
Пользовательский код не должен определять имена, начинающиеся с Py
или _Py
. Это сбивает читателя с толку и ставит под угрозу переносимость
пользовательского кода для будущих версий Python, которые могут определять
дополнительные имена, начинающиеся с одного из этих префиксов.
Файлы заголовков обычно устанавливаются вместе с Python. В Unix они расположены
в каталогах prefix/include/pythonversion/
и
exec_prefix/include/pythonversion/
, где prefix
и
exec_prefix
определяются соответствующими параметрами сценария Python
configure, а version — '%d.%d' % sys.version_info[:2]
. В
Windows заголовки устанавливаются в prefix/include
, где
prefix
— это каталог установки, указанный для установщика.
Чтобы включить заголовки, поместите оба каталога (если они разные) в путь
поиска вашего компилятора для include. Не помещайте родительские каталоги в
путь поиска, а затем использовать #include <pythonX.Y/Python.h>
; это не
работает в многоплатформенных сборках, поскольку независимые от платформы
заголовки в prefix
включают в себя специфичные для платформы
заголовки из exec_prefix
.
Пользователи C++ должны учитывать, что, хотя API полностью определён с
использованием C, файлы заголовков правильно объявляют точки входа как extern
"C"
. В результате для использования API из C++ не нужно делать ничего
особенного.
Полезные макросы¶
Несколько полезных макросов определены в файлах заголовков Python. Многие из
них определены ближе к тому месту, где они могут быть полезны (например,
Py_RETURN_NONE
). Здесь определяются другие, более общие полезности.
Это не обязательно полный список.
-
Py_UNREACHABLE
()¶ Используйте его, если у вас есть путь кода, который вы не ожидаете достичь. Например, в предложении
default:
в оператореswitch
, для которого все возможные значения описаны в операторахcase
. Используйте его там, где у вас может возникнуть соблазн отправить вызовassert(0)
илиabort()
.Добавлено в версии 3.7.
-
Py_ABS
(x)¶ Возвращает абсолютное значение
x
.Добавлено в версии 3.3.
-
Py_MIN
(x, y)¶ Возвращает минимальное значение от
x
доy
.Добавлено в версии 3.3.
-
Py_MAX
(x, y)¶ Возвращает максимальное значение между
x
иy
.Добавлено в версии 3.3.
-
Py_STRINGIFY
(x)¶ Преобразовать
x
в строку C. Например.Py_STRINGIFY(123)
возвращает"123"
.Добавлено в версии 3.4.
-
Py_MEMBER_SIZE
(type, member)¶ Возвращает размер структуры (
type
)member
в байтах.Добавлено в версии 3.6.
-
Py_CHARMASK
(c)¶ Аргумент должен быть символом или целым числом в диапазоне [-128, 127] или [0, 255]. Данный макрос возвращает преобразование
c
вunsigned char
.
-
Py_GETENV
(s)¶ Подобно
getenv(s)
, но возвращаетNULL
, если-E
был передан в командной строке (т. е. если заданоPy_IgnoreEnvironmentFlag
).
-
Py_UNUSED
(arg)¶ Используйте его для неиспользуемых аргументов в определении функции, чтобы отключить предупреждения компилятора. Пример:
int func(int a, int Py_UNUSED(b)) { return a; }
.Добавлено в версии 3.4.
-
Py_DEPRECATED
(version)¶ Используйте его для устаревших объявлений. Макрос должен быть помещён перед именем символа.
Пример:
Py_DEPRECATED(3.8) PyAPI_FUNC(int) Py_OldFunction(void);
Изменено в версии 3.8: Добавлена поддержка MSVC.
-
PyDoc_STRVAR
(name, str)¶ Создаёт переменную с именем
name
, которую можно использовать в строках документации. Если Python построен без строк документации, значение будет пустым.Использовать
PyDoc_STRVAR
для строк документации, чтобы поддерживать сборку Python без строк документации, как указано в PEP 7.Пример:
PyDoc_STRVAR(pop_doc, "Remove and return the rightmost element."); static PyMethodDef deque_methods[] = { // ... {"pop", (PyCFunction)deque_pop, METH_NOARGS, pop_doc}, // ... }
-
PyDoc_STR
(str)¶ Создаёт строку документации для данной входной строки или пустую строку, если строки документации отключены.
Использовать
PyDoc_STR
при указании строк документации для поддержки сборки Python без строк документации, как указано в PEP 7.Пример:
static PyMethodDef pysqlite_row_methods[] = { {"keys", (PyCFunction)pysqlite_row_keys, METH_NOARGS, PyDoc_STR("Returns the keys of the row.")}, {NULL, NULL} };
Объекты, типы и количество ссылок¶
У большинства функций API Python/C один или несколько аргументов, а также
возвращаемое значение типа PyObject*
. Данный тип является указателем
на непрозрачный тип данных, представляющий произвольный объект Python.
Поскольку все типы объектов Python обрабатываются языком Python одинаково в
большинстве ситуаций (например, присваивания, правила области видимости и
передача аргументов), вполне уместно, чтобы они были представлены одним типом
C. Почти все объекты Python находятся в куче: вы никогда не объявляете
автоматическую или статическую переменную типа PyObject
, можно
объявить только переменные-указатели типа PyObject*
. Единственное
исключение — это объекты типа; поскольку их никогда нельзя освобождать, они
обычно являются статическими объектами PyTypeObject
.
У всех объектов Python (даже целые числа Python) есть тип и
количество ссылок. Тип объекта определяет, что это за объект (например,
целое число, список или определяемая пользователем функция; их гораздо больше,
как приведено в Стандартная иерархия типов). Для каждого из хорошо известных типов существует
макрос, проверяющий, принадлежит ли объект этому типу; например,
PyList_Check(a)
истинно, если (и только если) объект, на который указывает
a, является списком Python.
Количество ссылок¶
Подсчёт ссылок важен, потому что у современных компьютеров есть конечный (и часто сильно ограниченный) размер памяти; он подсчитывает, у скольких разных мест есть ссылка на объект. Таким местом может быть другой объект, или глобальная (или статическая) C переменная, или локальная переменная в некоторой C функции. Когда счётчик ссылок на объект становится равным нулю, объект освобождается. Если он содержит ссылки на другие объекты, их счётчик ссылок уменьшается. Другие объекты могут быть освобождены по очереди, если это декремент сделает их счётчик ссылок равным нулю, и так далее. (Здесь очевидная проблема с объектами, которые ссылаются друг на друга; на данный момент решение: «Не делайте этого».)
Счётчиками ссылок всегда манипулируют явно. Обычный способ — использовать
макрос Py_INCREF()
для увеличения счётчика ссылок объекта на единицу и
Py_DECREF()
для уменьшения его на единицу. Макрос Py_DECREF()
значительно сложнее макроса incref, поскольку он должен проверять, становится
ли счётчик ссылок нулем, а затем вызывать освобождение объекта. Освободитель
— это указатель на функцию, содержащийся в структуре типа объекта.
Освободитель для заданного типа заботится об уменьшении счётчиков ссылок для
других объектов, содержащихся в объекте, если это составной тип объекта,
например, список, а также выполняет любую дополнительную необходимую
финализацию. Нет никаких шансов, что счётчик ссылок может переполниться; для
хранения счётчика ссылок используется по крайней мере столько же битов, сколько
существует различных ячеек памяти в виртуальной памяти (при условии
sizeof(Py_ssize_t) >= sizeof(void*)
). Таким образом, увеличение счётчика
ссылок — простая операция.
Нет необходимости увеличивать счётчик ссылок объекта для каждой локальной переменной, содержащей указатель на объект. Теоретически счётчик ссылок на объект увеличивается на единицу, когда переменная указывает на него, и уменьшается на единицу, когда переменная выходит за пределы области видимости. Однако эти двое взаимно компенсируют друг друга, поэтому в конце счётчик ссылок не изменился. Единственная реальная причина использовать счётчик ссылок — предотвратить освобождение объекта, пока наша переменная указывает на него. Если мы знаем, что существует хотя бы одна другая ссылка на объект, который живет по крайней мере столько же, сколько наша переменная, нет необходимости временно увеличивать счётчик ссылок. Важная ситуация, когда это возникает, — это передаваемые в качестве аргументов функциям C объекты в вызываемом из Python модуле расширения; механизм вызова гарантирует сохранение ссылки на каждый аргумент в течение всего вызова.
Однако распространенной ошибкой является извлечение объекта из списка и
удержание его в течение некоторого времени без увеличения его счётчика ссылок.
Другая операция могла бы предположительно удалить объект из списка, уменьшив
его счётчик ссылок и, возможно, освободив его. Реальная опасность состоит в
том, что невинно выглядящие операции могут вызвать произвольный код Python,
который может это сделать; существует реализация кода, позволяющая
передавать управление обратно пользователю с Py_DECREF()
, поэтому
практически любая операция потенциально опасна.
Безопасный подход — всегда использовать общие операции (функции, имена
которых начинаются с PyObject_
, PyNumber_
, PySequence_
или
PyMapping_
). Данные операции всегда увеличивают счётчик ссылок возвращаемого
объекта. Это оставляет вызывающему ответственность вызвать
Py_DECREF()
, когда они закончат работу с результатом; это скоро
становится второй натурой.
Сведения о количестве ссылок¶
Поведение функций в Python/C API счётчика ссылок лучше всего объясняется в
терминах владение ссылками. Владение относится к ссылкам, а
не к объектам (объекты не принадлежат: они всегда являются общими). «Владение
ссылкой» означает ответственность за вызов Py_DECREF для неё, когда ссылка
больше не нужна. Право владения также может быть передано, что означает,
что код, который получает право собственности на ссылку, затем становится
ответственным за её окончательное уменьшение, вызывая Py_DECREF()
или
Py_XDECREF()
, когда она больше не нужна ,— или передавая эту
ответственность (обычно вызывающей стороне). Когда функция передаёт владение
на ссылку своему вызывающему, говорят, что вызывающий получает
новую ссылку. Когда владение не передаётся, вызывающий
одалживает ссылку. Для заимствованной ссылки ничего делать не нужно.
И наоборот, когда вызывающая функция передаёт ссылку на объект, есть две возможности: функция крадёт ссылку на объект или нет. Кража ссылки означает, что при передаче ссылки на функцию, функция предполагает, что теперь она владеет этой ссылкой, и вы больше не несете за неё ответственности.
Некоторые функции крадут ссылки; двумя примечательными исключениями крадущими
ссылку на элемент являются PyList_SetItem()
и PyTuple_SetItem()
(но не на кортеж или список, в который данный элемент помещён!). Данные
функции были разработаны для кражи ссылки из-за общей идиомы для заполнения
кортежа или списка вновь созданными объектами; например, код для создания
кортежа (1, 2, "three")
может выглядеть следующим образом (забыв на данный
момент об обработке ошибок; лучший способ кодирования этого показан ниже):
PyObject *t;
t = PyTuple_New(3);
PyTuple_SetItem(t, 0, PyLong_FromLong(1L));
PyTuple_SetItem(t, 1, PyLong_FromLong(2L));
PyTuple_SetItem(t, 2, PyUnicode_FromString("three"));
Здесь PyLong_FromLong()
возвращает новую ссылку, которая сразу же
украдена PyTuple_SetItem()
. Если вы хотите продолжить использование
объекта, хотя ссылка на него будет украдена, использовать Py_INCREF()
,
чтобы захватить другую ссылку перед вызовом функции кражи ссылок.
Между прочим, PyTuple_SetItem()
— это способ только для установки
элементов кортежа; PySequence_SetItem()
и PyObject_SetItem()
отказываются делать это, поскольку кортежи являются неизменяемым типом данных.
Вы должны использовать PyTuple_SetItem()
только для кортежей, которые
вы создаёте сами.
Эквивалентный код для заполнения списка можно записать с использованием
PyList_New()
и PyList_SetItem()
.
Однако на практике вы редко будете использовать эти способы создания и
заполнения кортежа или списка. Существует общая функция
Py_BuildValue()
, которая может создавать наиболее распространенные
объекты из значений C, управляемых строкой форматирования. Например, два
вышеуказанных блока кода могут быть заменены следующим (который также заботится
о проверке ошибок):
PyObject *tuple, *list;
tuple = Py_BuildValue("(iis)", 1, 2, "three");
list = Py_BuildValue("[iis]", 1, 2, "three");
Гораздо более распространено использование PyObject_SetItem()
и друзей
с элементами, ссылки на которые вы только заимствуете, например,
переданные функции аргументы. В этом случае их поведение в
отношении счётчиков ссылок намного разумнее, поскольку вам не нужно увеличивать
счётчик ссылок, чтобы вы могли передать ссылку («пусть она будет украдена»).
Например, функция устанавливает все элементы списка (фактически, любую
изменяемую последовательность) на данный элемент:
int
set_all(PyObject *target, PyObject *item)
{
Py_ssize_t i, n;
n = PyObject_Length(target);
if (n < 0)
return -1;
for (i = 0; i < n; i++) {
PyObject *index = PyLong_FromSsize_t(i);
if (!index)
return -1;
if (PyObject_SetItem(target, index, item) < 0) {
Py_DECREF(index);
return -1;
}
Py_DECREF(index);
}
return 0;
}
Ситуация несколько иная для значений, возвращаемых функцией. Хотя передача
ссылки на большинство функций не изменяет ваши обязанности владения этой
ссылкой, многие функции, возвращающие ссылку на объект, предоставляют вам право
владения ссылкой. Причина проста: во многих случаях возвращаемый объект
создаётся «на лету», и полученная ссылка является единственной ссылкой на
объект. Поэтому универсальные функции, возвращающие ссылки на объекты, такие
как PyObject_GetItem()
и PySequence_GetItem()
, всегда
возвращают новую ссылку (вызывающий становится владельцем ссылки).
Важно понимать, что принадлежность возвращенной функцией ссылки,
зависит вызываемой функции — слив (plumage)
(тип объекта, переданного в качестве аргумента функции) не входит в него. Таким
образом, если извлекается элемент из списка с помощью
PyList_GetItem()
, вы не владеете ссылкой ,— но если получаете тот
же элемент из того же списка с помощью PySequence_GetItem()
(который
принимает точно такие же аргументы), то владеете ссылкой на возвращённый
объект.
Вот пример того, как вы могли бы написать функцию, которая вычисляет сумму
элементов в списке целых чисел; один раз с использованием
PyList_GetItem()
и один раз с помощью PySequence_GetItem()
.
long
sum_list(PyObject *list)
{
Py_ssize_t i, n;
long total = 0, value;
PyObject *item;
n = PyList_Size(list);
if (n < 0)
return -1; /* Не список */
for (i = 0; i < n; i++) {
item = PyList_GetItem(list, i); /* Не могу потерпеть неудачу */
if (!PyLong_Check(item)) continue; /* Пропускать нецелые числа */
value = PyLong_AsLong(item);
if (value == -1 && PyErr_Occurred())
/* Целое число слишком большое, чтобы поместиться в C long, спасайся */
return -1;
total += value;
}
return total;
}
long
sum_sequence(PyObject *sequence)
{
Py_ssize_t i, n;
long total = 0, value;
PyObject *item;
n = PySequence_Length(sequence);
if (n < 0)
return -1; /* Нет длины */
for (i = 0; i < n; i++) {
item = PySequence_GetItem(sequence, i);
if (item == NULL)
return -1; /* Не последовательность или другой сбой */
if (PyLong_Check(item)) {
value = PyLong_AsLong(item);
Py_DECREF(item);
if (value == -1 && PyErr_Occurred())
/* Целое число слишком большое, чтобы поместиться в long С, спасайся */
return -1;
total += value;
}
else {
Py_DECREF(item); /* Отказаться от владения ссылкой */
}
}
return total;
}
Типы¶
Есть несколько других играющих важную роль в API Python/C типов данных;
большинство из них — простые типы C, например, int
, long
,
double
и char*
. Несколько типов структур используются для
описания статических таблиц, используемых для перечисления функций,
экспортируемых модулем, или атрибутов данных нового типа объекта, а другой
используется для описания значения комплексного числа. Они будут обсуждаться
вместе с функциями, которые их используют.
Исключения¶
Программисту Python нужно работать с исключениями только в том случае, если требуется обработка ошибок; необработанные исключения автоматически передаются вызывающей стороне, затем вызывающей стороне и так далее, пока они не достигнут интерпретатора верхнего уровня, где они сообщаются пользователю в сопровождении трассировки стека.
Однако для программистов на C проверка ошибок всегда должна быть явной. Все
функции в Python/C API могут вызывать исключения, если иное явно не указано в
документации функции. Обычно, когда функция обнаруживает ошибку, она
устанавливает исключение, отбрасывает любые ссылки на объекты, которыми она
владеет, и возвращает индикатор ошибки. Если не указано иное, это индикатор
NULL
или -1
, в зависимости от типа возвращаемого значения функции.
Некоторые функции возвращают логический результат «истина/ложь», где ложь
указывает на ошибку. Очень немногие функции не возвращают явного индикатора
ошибки или имеют неоднозначное возвращаемое значение и требуют явного
тестирования на наличие ошибок с помощью PyErr_Occurred()
. Данные
исключения всегда явно документируются.
Состояние исключения поддерживается в хранилище для каждого потока (это
эквивалентно использованию глобального хранилища в приложении без потоков).
Поток может находиться в одном из двух состояний: возникло исключение или нет.
Для проверки этого можно использовать функцию PyErr_Occurred()
: она
возвращает заимствованную ссылку на объект типа исключения, когда возникло
исключение, и NULL
в противном случае. Существует ряд функций для установки
состояния исключения: PyErr_SetString()
— наиболее распространенная
(хотя и не самая общая) функция для установки состояния исключения, а
PyErr_Clear()
очищает состояние исключения.
Состояние полного исключения состоит из трёх объектов (каждый из которых может
быть NULL
): тип исключения, соответствующее значение исключения и
трассировка. Они имеют то же значение, что и результат Python
sys.exc_info()
; однако они не совпадают: объекты Python представляют собой
последнее исключение, обрабатываемое оператором Python try
…
except
, в то время как состояние исключения уровня C существует
только тогда, когда исключение передаётся между функциями C, пока оно не
достигнет Python основной цикл интерпретатора байт-кода, который заботится о
передаче его sys.exc_info()
и его друзьям.
Обратите внимание, что начиная с Python 1.5 предпочтительным
поточно-ориентированным способом доступа к состоянию исключения из кода Python является
вызов функции sys.exc_info()
, которая возвращает состояние исключения для
каждого потока для кода Python. Кроме того, семантика обоих способов доступа к
состоянию исключения изменилась, так что функция, перехватывающая исключение,
будет сохранять и восстанавливать состояние исключения своего потока, чтобы
сохранить состояние исключения вызывающей стороны. Это предотвращает
распространенные ошибки в коде обработки исключений, вызванные невинно
выглядящей функцией, перезаписывающей обрабатываемое исключение; это также
уменьшает часто нежелательное продление срока службы для объектов, на которые
ссылаются фреймы стека в трассировке.
Как правило, функция, которая вызывает другую функцию для выполнения некоторой задачи, должна проверять, вызвала ли вызываемая функция исключение, и, если да, передать состояние исключения вызывающей стороне. Она должна отбросить любые ссылки на собственные объекты и вернуть индикатор ошибки, но она не должна установить другое исключение, — которое перезапишет только что возникшее исключение и потеряет важную информацию о точной причине ошибки.
Простой пример обнаружения исключений и их передачи показан в примере
sum_sequence()
выше. Так получилось, что в этом примере не нужно
очищать какие-либо собственные ссылки при обнаружении ошибки. В следующем
примере функции показана некоторая очистка от ошибок. Во-первых, чтобы
напомнить вам, почему вам нравится Python, мы показываем эквивалентный код
Python:
def incr_item(dict, key):
try:
item = dict[key]
except KeyError:
item = 0
dict[key] = item + 1
Вот соответствующий C код во всей красе:
int
incr_item(PyObject *dict, PyObject *key)
{
/* Все объекты инициализированы в значение NULL для Py_XDECREF */
PyObject *item = NULL, *const_one = NULL, *incremented_item = NULL;
int rv = -1; /* Возвращаемое значение, инициализированное до -1 (ошибка) */
item = PyObject_GetItem(dict, key);
if (item == NULL) {
/* Обрабатывать только KeyError: */
if (!PyErr_ExceptionMatches(PyExc_KeyError))
goto error;
/* Удалить ошибку и использовать ноль: */
PyErr_Clear();
item = PyLong_FromLong(0L);
if (item == NULL)
goto error;
}
const_one = PyLong_FromLong(1L);
if (const_one == NULL)
goto error;
incremented_item = PyNumber_Add(item, const_one);
if (incremented_item == NULL)
goto error;
if (PyObject_SetItem(dict, key, incremented_item) < 0)
goto error;
rv = 0; /* Успех */
/* Продолжить с кодом очистки */
error:
/* Код очистки, разделяемый путем успеха и отказа */
/* Используйте Py_XDECREF(), чтобы игнорировать NULL ссылки */
Py_XDECREF(item);
Py_XDECREF(const_one);
Py_XDECREF(incremented_item);
return rv; /* -1 для ошибки, 0 для успеха */
}
Данный пример представляет одобренное использование оператора goto
в C! Он
иллюстрирует использование PyErr_ExceptionMatches()
и
PyErr_Clear()
для обработки определенных исключений и использование
Py_XDECREF()
для удаления собственных ссылок, которые могут быть
NULL
(обратите внимание на 'X'
в имени; Py_DECREF()
вылетит при
столкновении со ссылкой NULL
). Важно, чтобы переменные, используемые для
хранения собственных ссылок, были инициализированы как NULL
, чтобы это
работало; аналогично, предлагаемое возвращаемое значение инициализируется как
-1
(сбой) и устанавливается на успех только после того, как последний
сделанный вызов будет успешным.
Встраивание Python¶
Одна важная задача, о которой должны беспокоиться только разработчики (в отличие от разработчиков расширений) интерпретатора Python — это инициализация и, возможно, финализация интерпретатора Python. Большинство функций интерпретатора можно использовать только после его инициализации.
Основная функция инициализации — Py_Initialize()
. Она инициализирует
таблицу загруженных модулей и создаёт основные модули builtins
,
__main__
и sys
. Она также инициализирует путь поиска модуля
(sys.path
).
Py_Initialize()
не устанавливает «список аргументов сценария»
(sys.argv
). Если переменная необходима для кода Python, который будет
выполнен позже, она должна быть явно установлена с помощью вызова
PySys_SetArgvEx(argc, argv, updatepath)
после вызова
Py_Initialize()
.
В большинстве систем (в частности, в Unix и Windows, хотя детали немного
отличаются), Py_Initialize()
вычисляет путь поиска модуля на основе
наилучшего предположения о местонахождении стандартного исполняемого файла
интерпретатора Python, предполагая, что библиотека Python находится в
фиксированное расположение относительно исполняемого файла интерпретатора
Python. В частности, она ищет каталог с именем lib/pythonX.Y
относительно родительского каталога, где исполняемый файл с именем
python
находится в пути поиска команд оболочки (переменная среды
PATH
).
Например, если исполняемый файл Python находится в
/usr/local/bin/python
, предполагается, что библиотеки находятся в
/usr/local/lib/pythonX.Y
. (Фактически, данный путь также
является «резервным» местоположением, используемым, когда исполняемый файл с
именем python
не найден в PATH
.) Пользователь может
переопределить это поведение, установив переменную среды PYTHONHOME
или вставив дополнительные каталоги перед стандартными путями, установив
PYTHONPATH
.
Приложение для встраивания может управлять поиском, вызвав
перед Py_SetProgramName(file)
и вызвав Py_Initialize()
.
Обратите внимание, что PYTHONHOME
по-прежнему отменяет это, а
PYTHONPATH
по-прежнему вставляется перед стандартным путём.
Приложение, требующее полного контроля, должно предоставлять собственную
реализацию Py_GetPath()
, Py_GetPrefix()
,
Py_GetExecPrefix()
и Py_GetProgramFullPath()
(все они
определены в Modules/getpath.c
).
Иногда желательно «деинициализировать» Python. Например, приложение может
захотеть начать заново (сделать ещё один вызов Py_Initialize()
) или
приложение просто работает с использованием Python и хочет освободить память,
выделенную Python. Это можно сделать, вызвав
Py_FinalizeEx()
. Функция Py_IsInitialized()
возвращает истину,
если Python в настоящий момент находится в инициализированном состоянии. Более
подробная информация об этих функциях приведена в следующей главе. Обратите
внимание, что Py_FinalizeEx()
не освобождает всю память, выделенную
интерпретатором Python, например память, выделенная модулями расширения, в
настоящее время не может быть освобождена.
Отладка сборок¶
Python может быть построен с несколькими макросами, чтобы включить дополнительные проверки модулей интерпретатора и расширения. Эти проверки, как правило, увеличивают нагрузку на среду выполнения, поэтому по умолчанию они не включены.
Полный список различных типов отладочных сборок находится в файле
Misc/SpecialBuilds.txt
в дистрибутиве исходного кода Python. Доступны
сборки, поддерживающие отслеживание счётчиков ссылок, отладку распределителя
памяти или низкоуровневое профилирование основного цикла интерпретатора. В
оставшейся части этого раздела будут описаны только наиболее часто используемые
сборки.
Компиляция интерпретатора с определенным макросом Py_DEBUG
предоставляет то, что обычно понимается под «отладочной сборкой» Python. Py_DEBUG
включается в сборке Unix путем добавления --with-pydebug
к команде
./configure
. Это также подразумевается наличием не специфичного для
Python макроса _DEBUG
. Когда в сборке Unix включён
Py_DEBUG
, оптимизация компилятора отключена.
В дополнение к отладке счётчика ссылок, описанной ниже, выполняются следующие дополнительные проверки:
- В распределитель объектов добавляются дополнительные проверки.
- В парсер и компилятор добавлены дополнительные проверки.
- Отклонения от широких типов к узким проверяются на предмет потери информации.
- В словарь и множество реализаций добавлен ряд утверждений. Кроме того,
установленный объект получает метод
test_c_api()
. - При создании фрейма добавлены проверки корректности входных аргументов.
- Хранилище для целых чисел инициализируется известным недопустимым шаблоном для перехвата ссылки на неинициализированные цифры.
- В виртуальную машину среды выполнения добавлены низкоуровневая трассировка и дополнительная проверка исключений.
- В реализацию арены памяти добавлены дополнительные проверки.
- В модуль потока добавлена дополнительная отладка.
Могут быть дополнительные проверки, не упомянутые здесь.
Определение Py_TRACE_REFS
включает трассировку ссылок. Если
определено, круговой двусвязный список активных объектов поддерживается путём
добавления двух дополнительных полей к каждому PyObject
. Также
отслеживаются общие распределения. При выходе печатаются все существующие
ссылки. (В интерактивном режиме это происходит после каждого оператора,
выполняемого интерпретатором.) Подразумевается Py_DEBUG
.
Пожалуйста, обратитесь к Misc/SpecialBuilds.txt
в дистрибутиве
исходного кода Python для получения более подробной информации.