Введение
Интерфейс прикладного программирования Python предоставляет программистам на C и C++ доступ к интерпретатору Python на различных уровнях. API в равной степени можно использовать из C++, но для краткости его обычно называют Python/C API. Существует две принципиально разные причины использовать Python/C API. Первая — написание модулей расширения для конкретных задач; это модули на 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 до включения любых стандартных заголовков.
Рекомендуется всегда определять 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 задаются соответствующими параметрами скрипта Python configure, а 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 = { PyModuleDef_HEAD_INIT, .m_name = "spam", ... }; PyMODINIT_FUNC PyInit_spam(void) { return PyModule_Create(&spam_module); }
-
Py_ABS(x) -
Возвращает абсолютное значение
x.Добавлен в версии 3.3.
-
Py_ALWAYS_INLINE -
Предписывает компилятору всегда подставлять тело статической встраиваемой функции. Компилятор может проигнорировать это указание и отказаться от подстановки тела функции.
Этот макрос можно использовать для подстановки тел критичных к производительности статических встраиваемых функций при сборке Python в режиме отладки с отключённой подстановкой функций. Например, MSC отключает подстановку функций при сборке в режиме отладки.
Безоговорочное применение 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 обращается со всеми типами объектов 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(), всегда возвращают новую ссылку (вызывающая сторона становится её владельцем).
Важно понимать, что владение ссылкой, возвращённой функцией, зависит только от того, какую функцию вы вызываете, — оперение (тип объекта, переданного функции в качестве аргумента) никак не влияет на это! Поэтому, извлекая элемент из списка с помощью 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, в зависимости от типа возвращаемого функцией значения. Некоторые функции возвращают логический результат — истину или ложь, причём ложь указывает на ошибку. Очень немногие функции не возвращают явный индикатор ошибки или имеют неоднозначное возвращаемое значение и требуют явной проверки ошибок с помощью 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 находится в фиксированном месте относительно этого файла. В частности, она ищет каталог с именем lib/pythonX.Y относительно родительского каталога, в котором, согласно пути поиска команд оболочки (переменной окружения PATH), находится исполняемый файл с именем python.
Например, если исполняемый файл Python находится в /usr/local/bin/python, предполагается, что библиотеки расположены в /usr/local/lib/pythonX.Y. (На самом деле именно этот путь используется также как резервный, если в PATH не найден исполняемый файл с именем python.) Пользователь может переопределить это поведение, задав переменную окружения 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
Компиляция интерпретатора с определённым макросом Py_DEBUG создаёт сборку, которую обычно называют отладочной сборкой Python. В сборке для Unix Py_DEBUG включается добавлением --with-pydebug к команде ./configure. Кроме того, этот режим подразумевается при наличии макроса _DEBUG, не связанного исключительно с Python. При включённом Py_DEBUG в сборке для Unix оптимизация компилятора отключается.
Помимо описанной ниже отладки счётчиков ссылок, выполняются дополнительные проверки; см. раздел Отладочная сборка Python.
Определение Py_TRACE_REFS включает трассировку ссылок (см. параметр configure --with-trace-refs option). Если этот макрос определён, для активных объектов ведётся циклический двусвязный список: к каждому PyObject добавляются два дополнительных поля. Также отслеживается общее количество выделений памяти. При завершении работы выводятся все существующие ссылки. (В интерактивном режиме это происходит после каждого оператора, выполненного интерпретатором.)
Более подробные сведения приведены в файле Misc/SpecialBuilds.txt дистрибутива исходного кода Python.
© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/c-api/intro.html