Введение
Интерфейс прикладного программирования Python предоставляет программистам на C и C++ доступ к интерпретатору Python на различных уровнях. API в равной степени пригоден для использования из C++, но для краткости его обычно называют Python/C API. Существует две принципиально разные причины использовать Python/C API. Первая — написание модулей расширения для определённых целей; это модули на C, расширяющие интерпретатор 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 до включения любых стандартных заголовков.
Рекомендуется всегда определять PY_SSIZE_T_CLEAN перед включением Python.h. Описание этого макроса см. в разделе Разбор аргументов и создание значений.
Все имена, видимые пользователю и определённые в Python.h (за исключением имён из включённых стандартных заголовков), имеют префикс Py или _Py. Имена, начинающиеся с _Py, предназначены для внутреннего использования реализацией Python и не должны использоваться разработчиками расширений. Имена членов структур не имеют зарезервированного префикса.
Примечание
Пользовательский код никогда не должен определять имена, начинающиеся с Py или _Py. Это затрудняет чтение кода и ставит под угрозу его переносимость на будущие версии Python, в которых могут появиться дополнительные имена с одним из этих префиксов.
Файлы заголовков обычно устанавливаются вместе с Python. В Unix они находятся в каталогах prefix/include/pythonversion/ и exec_prefix/include/pythonversion/, где prefix и exec_prefix задаются соответствующими параметрами скрипта configure Python, а version — это '%d.%d' % sys.version_info[:2]. В Windows заголовки устанавливаются в prefix/include, где prefix — это каталог установки, указанный программе установки.
Чтобы включить заголовки, добавьте оба каталога (если они различаются) в путь поиска подключаемых файлов компилятора. Не добавляйте в путь поиска родительские каталоги, а затем используйте #include <pythonX.Y/Python.h>; это нарушит сборки для нескольких платформ, поскольку независимые от платформы заголовки в prefix включают заголовки, специфичные для платформы, из exec_prefix.
Пользователям C++ следует учесть, что, хотя API полностью определён с использованием C, в файлах заголовков точки входа правильно объявлены как extern "C". Поэтому для использования API из C++ не требуется никаких специальных действий.
Полезные макросы
В файлах заголовков Python определено несколько полезных макросов. Многие из них определены рядом с местом, где они используются (например, Py_RETURN_NONE). Другие макросы общего назначения определены здесь. Этот список не обязательно является исчерпывающим.
-
PyMODINIT_FUNC -
Объявляет функцию инициализации
PyInitмодуля расширения. Тип возвращаемого функцией значения — PyObject*. Макрос объявляет специальные спецификаторы связывания, требуемые платформой, а для C++ объявляет функцию какextern "C".Функция инициализации должна называться
PyInit_name, где name — имя модуля, и быть единственным элементом, не являющимсяstatic, определённым в файле модуля. Пример:static struct PyModuleDef spam_module = { .m_base = PyModuleDef_HEAD_INIT, .m_name = "spam", ... }; PyMODINIT_FUNC PyInit_spam(void) { return PyModuleDef_Init(&spam_module); }
-
Py_ABS(x) -
Возвращает абсолютное значение
x.Добавлено в версии 3.3.
-
Py_ALWAYS_INLINE -
Просит компилятор всегда встраивать статическую inline-функцию. Компилятор может проигнорировать это указание и решить не встраивать функцию.
Макрос можно использовать для встраивания критически важных с точки зрения производительности статических inline-функций при сборке Python в режиме отладки с отключённым встраиванием функций. Например, MSC отключает встраивание функций при сборке в режиме отладки.
Без разбора помечать статическую inline-функцию макросом Py_ALWAYS_INLINE может привести к снижению производительности (например, из-за увеличения размера кода). Обычно компилятор лучше разработчика оценивает соотношение затрат и преимуществ.
Если Python собран в режиме отладки (если определён макрос
Py_DEBUG), макросPy_ALWAYS_INLINEничего не делает.Его необходимо указывать перед типом возвращаемого функцией значения. Использование:
static inline Py_ALWAYS_INLINE int random(void) { return 4; }Добавлено в версии 3.11.
-
Py_CHARMASK(c) -
Аргумент должен быть символом или целым числом в диапазоне [-128, 127] или [0, 255]. Этот макрос возвращает
c, приведённое к типуunsigned char.
-
Py_DEPRECATED(version) -
Используйте этот макрос для объявлений устаревших элементов. Макрос необходимо разместить перед именем символа.
Пример:
Py_DEPRECATED(3.8) PyAPI_FUNC(int) Py_OldFunction(void);
Изменено в версии 3.8: Добавлена поддержка MSVC.
-
Py_GETENV(s) -
Подобно
getenv(s), но возвращаетNULL, если в командной строке был передан параметр-E(см.PyConfig.use_environment).
-
Py_MAX(x, y) -
Возвращает наибольшее из значений
xиy.Добавлено в версии 3.3.
-
Py_MEMBER_SIZE(type, member) -
Возвращает размер члена структуры (
type)memberв байтах.Добавлено в версии 3.6.
-
Py_MIN(x, y) -
Возвращает наименьшее из значений
xиy.Добавлено в версии 3.3.
-
Py_NO_INLINE -
Отключает встраивание функции. Например, это позволяет снизить потребление стека C: полезно при сборках с LTO+PGO, которые активно встраивают код (см. bpo-33720).
Использование:
Py_NO_INLINE static int random(void) { return 4; }Добавлено в версии 3.11.
-
Py_STRINGIFY(x) -
Преобразует
xв строку C. Например,Py_STRINGIFY(123)возвращает"123".Добавлено в версии 3.4.
-
Py_UNREACHABLE() -
Используйте этот макрос, если по замыслу существует путь выполнения, который не может быть достигнут. Например, в ветви
default:оператораswitch, для которой все возможные значения охвачены операторамиcase. Используйте его в местах, где можно было бы поддаться искушению добавить вызовassert(0)илиabort().В режиме выпуска макрос помогает компилятору оптимизировать код и позволяет избежать предупреждения о недостижимом коде. Например, в GCC в режиме выпуска макрос реализован с помощью
__builtin_unreachable().Макрос
Py_UNREACHABLE()можно использовать после вызова функции, которая никогда не возвращает управление, но не объявлена как_Py_NO_RETURN.Если путь выполнения очень маловероятен, но может быть пройден в исключительном случае, этот макрос использовать нельзя. Например, при нехватке памяти или если системный вызов возвращает значение за пределами ожидаемого диапазона. В этом случае лучше сообщить об ошибке вызывающему коду. Если сообщить вызывающему коду об ошибке невозможно, можно использовать
Py_FatalError().Добавлено в версии 3.7.
-
Py_UNUSED(arg) -
Используйте этот макрос для неиспользуемых аргументов в определении функции, чтобы отключить предупреждения компилятора. Пример:
int func(int a, int Py_UNUSED(b)) { return a; }.Добавлено в версии 3.4.
-
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} };
Объекты, типы и счётчики ссылок
Большинство функций Python/C API принимают один или несколько аргументов и возвращают значение типа PyObject*. Этот тип представляет собой указатель на непрозрачный тип данных, представляющий произвольный объект Python. Поскольку язык Python в большинстве ситуаций одинаково обрабатывает объекты всех типов (например, при присваивании, соблюдении правил областей видимости и передаче аргументов), вполне естественно представлять их одним типом C. Почти все объекты Python размещаются в куче: вы никогда не объявляете автоматическую или статическую переменную типа PyObject, можно объявлять только переменные-указатели типа PyObject*. Единственное исключение — объекты типов; поскольку их нельзя освобождать, обычно это статические объекты PyTypeObject.
У всех объектов Python (даже целых чисел Python) есть тип и счётчик ссылок. Тип объекта определяет, что это за объект (например, целое число, список или пользовательская функция; существует множество других типов, описанных в разделе Стандартная иерархия типов). Для каждого из широко известных типов есть макрос, проверяющий, относится ли объект к этому типу; например, PyList_Check(a) имеет значение true тогда и только тогда, когда объект, на который указывает 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(), всегда возвращают новую ссылку (вызывающая сторона становится владельцем ссылки).
Важно понимать, что владение ссылкой, возвращённой функцией, зависит только от того, какую функцию вы вызываете: «оперение» (тип объекта, переданного функции в качестве аргумента) не имеет значения! Поэтому, если извлечь элемент из списка с помощью 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; /* Not a list */
for (i = 0; i < n; i++) {
item = PyList_GetItem(list, i); /* Can't fail */
if (!PyLong_Check(item)) continue; /* Skip non-integers */
value = PyLong_AsLong(item);
if (value == -1 && PyErr_Occurred())
/* Integer too big to fit in a C long, bail out */
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; /* Has no length */
for (i = 0; i < n; i++) {
item = PySequence_GetItem(sequence, i);
if (item == NULL)
return -1; /* Not a sequence, or other failure */
if (PyLong_Check(item)) {
value = PyLong_AsLong(item);
Py_DECREF(item);
if (value == -1 && PyErr_Occurred())
/* Integer too big to fit in a C long, bail out */
return -1;
total += value;
}
else {
Py_DECREF(item); /* Discard reference ownership */
}
}
return total;
}
Типы
В Python/C API значимую роль играют лишь несколько других типов данных; большинство из них — простые типы C, такие как int, long, double и char*. Некоторые типы структур используются для описания статических таблиц, в которых перечислены функции, экспортируемые модулем, или атрибуты данных нового типа объекта; ещё один тип используется для описания значения комплексного числа. Эти типы будут рассмотрены вместе с использующими их функциями.
-
type Py_ssize_t -
Часть стабильного ABI.
Знаковый целочисленный тип, для которого
sizeof(Py_ssize_t) == sizeof(size_t). Стандарт C99 напрямую не определяет такой тип (size_t — беззнаковый целочисленный тип). Подробности см. в PEP 353.PY_SSIZE_T_MAX— наибольшее положительное значение типаPy_ssize_t.
Исключения
Программисту на Python нужно работать с исключениями только в том случае, если требуется особая обработка ошибок; необработанные исключения автоматически передаются вызывающему коду, затем вызывающему коду этого кода и так далее, пока не достигнут интерпретатора верхнего уровня, где о них сообщается пользователю вместе с трассировкой стека.
Однако программистам на C всегда необходимо явно проверять ошибки. Все функции Python/C API могут возбуждать исключения, если только в документации функции явно не указано обратное. Как правило, при обнаружении ошибки функция устанавливает исключение, освобождает принадлежащие ей ссылки на объекты и возвращает индикатор ошибки. Если не указано иное, этим индикатором является NULL или -1 — в зависимости от типа возвращаемого функцией значения. Некоторые функции возвращают логический результат true/false, где false указывает на ошибку. Очень немногие функции не возвращают явный индикатор ошибки или имеют неоднозначное возвращаемое значение и требуют явной проверки ошибок с помощью 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)
{
/* Objects all initialized to NULL for Py_XDECREF */
PyObject *item = NULL, *const_one = NULL, *incremented_item = NULL;
int rv = -1; /* Return value initialized to -1 (failure) */
item = PyObject_GetItem(dict, key);
if (item == NULL) {
/* Handle KeyError only: */
if (!PyErr_ExceptionMatches(PyExc_KeyError))
goto error;
/* Clear the error and use zero: */
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; /* Success */
/* Continue with cleanup code */
error:
/* Cleanup code, shared by success and failure path */
/* Use Py_XDECREF() to ignore NULL references */
Py_XDECREF(item);
Py_XDECREF(const_one);
Py_XDECREF(incremented_item);
return rv; /* -1 for error, 0 for success */
}
Этот пример демонстрирует одобренное применение оператора 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, который будет выполнен позднее, необходимо задать PyConfig.argv и PyConfig.parse_argv: см. Конфигурация инициализации Python.
В большинстве систем (в частности, в 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.
Встраивающее приложение может управлять поиском, задав PyConfig.program_name до вызова Py_InitializeFromConfig(). Обратите внимание: PYTHONHOME по-прежнему переопределяет это значение, а PYTHONPATH по-прежнему добавляется перед стандартным путём. Приложение, которому требуется полный контроль, должно предоставить собственные реализации Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix() и Py_GetProgramFullPath() (все они определены в Modules/getpath.c).
Иногда бывает желательно «деинициализировать» Python. Например, приложение может захотеть начать заново (повторно вызвать Py_Initialize()) или просто завершить работу с Python и освободить память, выделенную Python. Для этого можно вызвать Py_FinalizeEx(). Функция Py_IsInitialized() возвращает true, если Python в данный момент инициализирован. Подробнее об этих функциях рассказано в одной из следующих глав. Обратите внимание: Py_FinalizeEx() не освобождает всю память, выделенную интерпретатором Python; например, память, выделенную модулями расширений, в настоящее время освободить невозможно.
Отладочные сборки
Python можно собрать с несколькими макросами, включающими дополнительные проверки интерпретатора и модулей расширений. Эти проверки создают значительную дополнительную нагрузку во время выполнения, поэтому по умолчанию они отключены.
Полный список различных типов отладочных сборок находится в файле Misc/SpecialBuilds.txt из дистрибутива исходного кода Python. Доступны сборки с отслеживанием счётчиков ссылок, отладкой распределителя памяти и низкоуровневым профилированием главного цикла интерпретатора. В оставшейся части этого раздела описаны только наиболее часто используемые сборки.
-
Py_DEBUG
Компиляция интерпретатора с определённым макросом Py_DEBUG создаёт сборку, которую обычно называют отладочной сборкой Python. В сборке для Unix макрос Py_DEBUG включается добавлением --with-pydebug к команде ./configure. Его также подразумевает наличие макроса _DEBUG, не относящегося исключительно к Python. При включённом в сборке для Unix макросе Py_DEBUG оптимизация компилятора отключается.
Помимо описанной ниже отладки счётчика ссылок выполняются дополнительные проверки; см. Отладочная сборка Python.
Определение Py_TRACE_REFS включает отслеживание ссылок (см. configure --with-trace-refs option). При его использовании для всех активных объектов поддерживается двусвязный циклический список; для этого в каждый PyObject добавляются два дополнительных поля. Также отслеживается общее количество выделений памяти. При завершении печатаются все существующие ссылки. (В интерактивном режиме это происходит после каждого оператора, выполненного интерпретатором.)
Дополнительные сведения см. в Misc/SpecialBuilds.txt из дистрибутива исходного кода Python.
Рекомендуемые сторонние инструменты
Следующие сторонние инструменты предлагают как более простые, так и более продвинутые способы создания расширений Python на C, C++ и Rust:
Использование подобных инструментов помогает избежать написания кода, тесно привязанного к определённой версии CPython, ошибок подсчёта ссылок и позволяет уделять больше внимания собственному коду, а не работе с CPython API. Как правило, для поддержки новых версий Python достаточно обновить инструмент, а ваш код зачастую автоматически будет использовать более новые и эффективные API. Некоторые инструменты также поддерживают сборку для других реализаций Python из одного набора исходных файлов.
Эти проекты не поддерживаются теми же людьми, которые сопровождают Python; о проблемах следует сообщать непосредственно разработчикам проектов. Не забывайте проверять, что проект по-прежнему поддерживается и развивается, поскольку приведённый выше список может устареть.
См. также
- Руководство пользователя по упаковке Python: бинарные расширения
-
Руководство пользователя по упаковке Python не только описывает несколько доступных инструментов, упрощающих создание бинарных расширений, но и рассматривает различные причины, по которым вообще может быть полезно создать модуль расширения.
© 2001–2025 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/c-api/intro.html