Введение
Интерфейс программиста для Python предоставляет программистам на C и C++ доступ к интерпретатору Python на различных уровнях. Интерфейс также пригоден для 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, а версия — '%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().В режиме выпуска макрос помогает компилятору оптимизировать код и избежать предупреждений об недостижимом коде. Например, макрос реализован с помощью
__builtin_unreachable()в GCC в режиме выпуска.Применение для
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) истинно, если (и только если) объект, на который указывает 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 относительно родительского каталога, где на пути поиска командной оболочки (переменная среды PATH).
Например, если исполняемый файл Python находится в /usr/local/bin/python, она предположит, что библиотеки находятся в /usr/local/lib/pythonX.Y. (Фактически, этот конкретный путь также является «падением» на случай, если ни один исполняемый файл под названием python не найден по PATH). Пользователь может переопределить это поведение, установив переменную среды PYTHONHOME или добавить дополнительные каталоги перед стандартным путём, установив PYTHONPATH.
Приложение, встраивающее Python, может направить поиск, вызвав 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() возвращает true, если Python в настоящее время находится в инициализированном состоянии. Более подробная информация об этих функциях приводится в последующей главе. Обратите внимание, что Py_FinalizeEx() не освобождает всю память, выделенную интерпретатором Python, например, память, выделенная расширяемыми модулями в настоящее время, не может быть освобождена.
Сборки отладки
Python может быть скомпилирован с несколькими макросами для включения дополнительных проверок интерпретатора и модулей расширений. Эти проверки, как правило, добавляют значительную нагрузку на время выполнения, поэтому они по умолчанию не включены.
Полный список различных типов сборок отладки находится в файле Misc/SpecialBuilds.txt в дистрибутиве исходного кода Python. Доступны сборки, которые поддерживают отслеживание ссылок, отладку выделения памяти или низкоуровневое профилирование основного цикла интерпретатора. В оставшейся части этого раздела будут описаны только наиболее часто используемые сборки.
-
Py_DEBUG
Компиляция интерпретатора с определённым макросом Py_DEBUG создаёт то, что обычно подразумевается под сборкой отладки Python. Py_DEBUG включено в сборке для Unix путём добавления --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