Введение

Интерфейс прикладного программиста для Python предоставляет программистам на C и C++ доступ к интерпретатору Python на различных уровнях. API можно использовать и из C++, но для краткости его принято называть Python/C API. Есть две принципиально разные причины для использования Python/C API. Первая причина - написание модулей расширения для конкретных целей; это модули на Си, расширяющие интерпретатор Python. Это, вероятно, наиболее распространенное использование. Вторая причина - использование Python в качестве компонента в более крупном приложении; эту технику обычно называют embedding Python в приложении.

Написание модуля расширения - это относительно хорошо понятный процесс, в котором хорошо работает подход «поваренной книги». Существует несколько инструментов, которые в некоторой степени автоматизируют этот процесс. Хотя люди встраивают Python в другие приложения с самого начала его существования, процесс встраивания Python менее прост, чем написание расширения.

Многие функции API полезны независимо от того, внедряете вы Python или расширяете его; более того, большинство приложений, внедряющих Python, должны будут предоставлять пользовательские расширения, так что, вероятно, будет полезно ознакомиться с написанием расширений, прежде чем пытаться внедрить Python в реальное приложение.

Стандарты кодирования

Если вы пишете код на Си для включения в 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, а версия равна '%d.%d' % sys.version_info[:2]. В Windows заголовки устанавливаются в prefix/include, где prefix - каталог установки, указанный программе установки.

Чтобы включить заголовки, поместите обе директории (если они разные) в путь поиска include вашего компилятора. Не размещайте родительские каталоги на пути поиска и не используйте #include <pythonX.Y/Python.h>; это приведет к сбоям в мультиплатформенных сборках, поскольку независимые от платформы заголовки в prefix включают специфичные для платформы заголовки из exec_prefix.

Пользователи C++ должны заметить, что, хотя API полностью определен на языке C, в заголовочных файлах точки входа правильно объявлены как extern "C". В результате для использования API из C++ не нужно делать ничего особенного.

Полезные макросы

Несколько полезных макросов определены в заголовочных файлах Python. Многие из них определены ближе к месту, где они полезны (например, Py_RETURN_NONE). Другие, имеющие более общее значение, определены здесь. Это не обязательно полный список.

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.

Added in version 3.3.

Py_ALWAYS_INLINE

Попросите компилятор всегда инлайнить статическую инлайн-функцию. Компилятор может проигнорировать это и решить не инлайнить функцию.

Его можно использовать для инлайнинга критичных к производительности статических инлайн-функций при сборке Python в режиме отладки с отключенным инлайнингом функций. Например, MSC отключает инлайнинг функций при сборке в режиме отладки.

Пометка статической inline-функции вслепую с помощью Py_ALWAYS_INLINE может привести к ухудшению производительности (например, из-за увеличения размера кода). Компилятор обычно умнее разработчика в плане анализа затрат и выгод.

Если Python равен built in debug mode (если определен макрос Py_DEBUG), макрос Py_ALWAYS_INLINE ничего не делает.

Он должен быть указан перед типом возврата функции. Использование:

static inline Py_ALWAYS_INLINE int random(void) { return 4; }

Added in version 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.

Added in version 3.3.

Py_MEMBER_SIZE(type, member)

Возвращает размер структуры (type) member в байтах.

Added in version 3.6.

Py_MIN(x, y)

Возвращает минимальное значение между x и y.

Added in version 3.3.

Py_NO_INLINE

Отключает инлайнинг в функции. Например, это уменьшает потребление стека C: полезно для сборок LTO+PGO, которые сильно инлайнят код (см. bpo-33720).

Использование:

Py_NO_INLINE static int random(void) { return 4; }

Added in version 3.11.

Py_STRINGIFY(x)

Преобразуйте x в строку C. Например, Py_STRINGIFY(123) возвращает "123".

Added in version 3.4.

Py_UNREACHABLE()

Используйте этот способ, когда у вас есть путь кода, который не может быть достигнут при проектировании. Например, в предложении default: в операторе switch, для которого все возможные значения охватываются операторами case. Используйте его в местах, где может возникнуть соблазн поместить вызов assert(0) или abort().

В режиме выпуска макрос помогает компилятору оптимизировать код и избежать предупреждения о недостижимом коде. Например, в GCC в режиме релиза макрос реализован со значением __builtin_unreachable().

Использование Py_UNREACHABLE() происходит после вызова функции, которая никогда не возвращается, но которая не объявлена _Py_NO_RETURN.

Если путь кода очень маловероятен, но может быть достигнут в исключительном случае, этот макрос не должен использоваться. Например, в условиях нехватки памяти или если системный вызов возвращает значение, выходящее за пределы ожидаемого диапазона. В этом случае лучше сообщить об ошибке вызывающей стороне. Если об ошибке нельзя сообщить вызывающей стороне, можно использовать Py_FatalError().

Added in version 3.7.

Py_UNUSED(arg)

Используйте этот параметр для неиспользуемых аргументов в определении функции, чтобы заглушить предупреждения компилятора. Пример: int func(int a, int Py_UNUSED(b)) { return a; }.

Added in version 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)

Создает docstring для заданной строки ввода или пустую строку, если docstrings отключены.

Используйте PyDoc_STR при указании docstrings для поддержки сборки Python без docstrings, как указано в 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 (даже целые числа) имеют тип type и reference count. Тип объекта определяет, к какому типу он относится (например, целое число, список или определяемая пользователем функция; существует множество других типов, о которых рассказывается в Стандартная иерархия типов). Для каждого из известных типов существует макрос для проверки принадлежности объекта к этому типу; например, PyList_Check(a) истинно, если (и только если) объект, на который указывает a, является списком Python.

Контрольные подсчеты

Счетчик ссылок важен, потому что современные компьютеры имеют конечный (и часто сильно ограниченный) объем памяти; он подсчитывает, сколько существует различных мест, которые имеют ссылку strong reference на объект. Таким местом может быть другой объект, или глобальная (или статическая) переменная языка C, или локальная переменная в какой-либо функции языка C. Когда последний strong reference на объект освобождается (т. е. количество ссылок становится равным нулю), объект деаллоцируется. Если он содержит ссылки на другие объекты, эти ссылки освобождаются. Эти другие объекты могут быть деаллоцированы в свою очередь, если на них больше нет ссылок, и так далее. (Здесь возникает очевидная проблема с объектами, которые ссылаются друг на друга; пока что решением является «не делайте этого»).

Счетчиками ссылок всегда манипулируют явно. Обычным способом является использование макроса Py_INCREF() для получения новой ссылки на объект (т. е. увеличения количества ссылок на единицу) и Py_DECREF() для освобождения этой ссылки (т. е. уменьшения количества ссылок на единицу). Макрос Py_DECREF() значительно сложнее, чем incref, поскольку он должен проверить, не стал ли счетчик ссылок нулевым, а затем вызвать деаллокатор объекта. Деаллокатор - это указатель функции, содержащийся в структуре типа объекта. Деаллокатор, специфичный для типа, заботится об освобождении ссылок для других объектов, содержащихся в объекте, если это составной тип объекта, например список, а также выполняет любую дополнительную финализацию, которая необходима. Вероятность переполнения счетчика ссылок исключена; для хранения счетчика ссылок используется по крайней мере столько же битов, сколько отдельных ячеек памяти в виртуальной памяти (при условии sizeof(Py_ssize_t) >= sizeof(void*)). Таким образом, инкремент счетчика ссылок - это простая операция.

Нет необходимости сохранять strong reference (то есть увеличивать счетчик ссылок) для каждой локальной переменной, содержащей указатель на объект. Теоретически, счетчик ссылок на объект увеличивается на единицу, когда переменная указывает на него, и уменьшается на единицу, когда переменная выходит из области видимости. Однако эти два фактора отменяют друг друга, так что в итоге счетчик ссылок не меняется. Единственная реальная причина использовать счетчик ссылок - это предотвратить удаление объекта, пока на него указывает наша переменная. Если мы знаем, что существует хотя бы одна другая ссылка на объект, которая живет по крайней мере столько же, сколько наша переменная, то нет необходимости временно брать новую strong reference (то есть увеличивать счетчик ссылок). Важной ситуацией, в которой это возникает, являются объекты, передаваемые в качестве аргументов функциям C в модуле расширения, которые вызываются из Python; механизм вызова гарантирует, что ссылка на каждый аргумент будет храниться в течение всего времени вызова.

Однако часто встречающийся подводный камень - это извлечение объекта из списка и удержание его в течение некоторого времени без получения новой ссылки. Какая-то другая операция, возможно, удалит объект из списка, освободив ссылку и, возможно, деаллоцировав ее. Реальная опасность заключается в том, что невинные с виду операции могут вызвать произвольный код Python, который может это сделать; существует путь кода, который позволяет передавать управление обратно пользователю из Py_DECREF(), поэтому практически любая операция потенциально опасна.

Безопасный подход заключается в том, чтобы всегда использовать общие операции (функции, имя которых начинается с PyObject_, PyNumber_, PySequence_ или PyMapping_). Эти операции всегда создают новый strong reference (т. е. увеличивают количество ссылок) возвращаемого объекта. Таким образом, на вызывающего пользователя возлагается ответственность за вызов Py_DECREF(), когда он закончит работу с результатом; вскоре это становится второй натурой.

Счетчик ссылок Подробнее

Поведение функций в API Python/C, связанное с подсчетом ссылок, лучше всего объясняется в терминах владения ссылками. Владение относится к ссылкам, а не к объектам (объекты не принадлежат: они всегда общие). «Владеть ссылкой» означает быть ответственным за вызов Py_DECREF, когда ссылка больше не нужна. Право собственности также может быть передано, то есть код, получивший право собственности на ссылку, становится ответственным за ее освобождение путем вызова Py_DECREF() или Py_XDECREF(), когда она больше не нужна - или передает эту ответственность (обычно своему вызывающему пользователю). Когда функция передает право собственности на ссылку своему вызывающему пользователю, говорят, что он получает новую ссылку. Когда право собственности не передается, говорят, что вызывающая функция заимствует ссылку. Для borrowed reference ничего не нужно делать.

И наоборот, когда вызывающая функция передает ссылку на объект, есть две возможности: функция устанавливает ссылку на объект или не устанавливает. Удаление ссылки означает, что когда вы передаете ссылку функции, эта функция считает, что теперь она владеет этой ссылкой, и вы больше не несете за нее ответственности.

Немногие функции крадут ссылки; два заметных исключения - 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, направляемых format string. Например, два приведенных выше блока кода можно заменить следующим (который также позаботится о проверке ошибок):

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 нужно иметь дело с исключениями только в том случае, если требуется специальная обработка ошибок; необработанные исключения автоматически передаются вызывающему устройству, затем вызывающему устройству вызывающего устройства и так далее, пока не достигнут интерпретатора верхнего уровня, где о них сообщается пользователю вместе с трассировкой стека.

Однако для программистов на Си проверка ошибок всегда должна быть явной. Все функции в Python/C API могут вызывать исключения, если в документации к функции явно не указано обратное. В общем случае, когда функция сталкивается с ошибкой, она создает исключение, отбрасывает все принадлежащие ей ссылки на объекты и возвращает индикатор ошибки. Если в документации не указано иное, этот индикатор равен либо NULL, либо -1, в зависимости от возвращаемого функцией типа. Некоторые функции возвращают булевский результат true/false, причем false означает ошибку. Очень немногие функции не возвращают явного индикатора ошибки или имеют неоднозначное возвращаемое значение и требуют явной проверки на ошибки с помощью PyErr_Occurred(). Такие исключения всегда явно документируются.

Состояние исключений хранится в потоковом хранилище (это эквивалентно использованию глобального хранилища в непотоковом приложении). Поток может находиться в одном из двух состояний: произошло исключение или нет. Для проверки этого состояния можно использовать функцию PyErr_Occurred(): она возвращает заимствованную ссылку на объект типа исключения, если исключение произошло, и NULL в противном случае. Существует несколько функций для установки состояния исключения: PyErr_SetString() является наиболее распространенной (хотя и не самой общей) функцией для установки состояния исключения, а PyErr_Clear() очищает состояние исключения.

Полное состояние исключения состоит из трех объектов (все они могут быть NULL): тип исключения, соответствующее значение исключения и отслеживание. Они имеют те же значения, что и результат Python sys.exc_info(); однако это не одно и то же: объекты Python представляют последнее исключение, обрабатываемое оператором Python tryexcept, в то время как состояние исключения на уровне 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 (неудача) и устанавливается в значение success только после успешного завершения последнего вызова.

Встраивание Python

Единственная важная задача, о которой приходится беспокоиться только встраивателям (в отличие от авторов расширений) интерпретатора Python, - это инициализация и, возможно, завершение работы интерпретатора Python. Большинство функциональных возможностей интерпретатора можно использовать только после его инициализации.

Основной функцией инициализации является Py_Initialize(). Она инициализирует таблицу загруженных модулей и создает фундаментальные модули builtins, __main__ и sys. Она также инициализирует путь поиска модулей (sys.path).

Py_Initialize() не задает «список аргументов скрипта» (sys.argv). Если эта переменная нужна коду Python, который будет выполняться позже, необходимо задать параметры PyConfig.argv и PyConfig.parse_argv: см. Python Initialization Configuration.

В большинстве систем (в частности, в Unix и Windows, хотя детали немного отличаются) Py_Initialize() вычисляет путь поиска модуля на основе наилучшего предположения о местоположении стандартного исполняемого файла интерпретатора Python, предполагая, что библиотека Python находится в фиксированном месте относительно исполняемого файла интерпретатора Python. В частности, он ищет каталог с именем lib/pythonX.Y относительно родительского каталога, в котором находится исполняемый файл с именем python в пути поиска команд оболочки (переменная окружения PATH).

Например, если исполняемый файл Python находится в каталоге /usr/local/bin/python, то предполагается, что библиотеки находятся в каталоге /usr/local/lib/pythonX.Y. (На самом деле, этот путь также является «запасным», используемым, если в каталоге PATH не найден исполняемый файл с именем python). Пользователь может отменить это поведение, задав переменную окружения 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 дает то, что обычно подразумевается под a debug build of Python. Py_DEBUG включается в Unix-сборке добавлением --with-pydebug к команде ./configure. Это также подразумевается наличием неспецифического для Python макроса _DEBUG. Когда Py_DEBUG включен в сборке Unix, оптимизация компилятора отключена.

В дополнение к отладке подсчета ссылок, описанной ниже, выполняются дополнительные проверки, см. Python Debug Build.

Определение Py_TRACE_REFS включает трассировку ссылок (см. configure --with-trace-refs option). При определении PyObject ведется круговой двусвязный список активных объектов путем добавления двух дополнительных полей в каждый PyObject. Также отслеживается общее количество выделений. При выходе распечатываются все существующие ссылки. (В интерактивном режиме это происходит после каждого оператора, выполняемого интерпретатором).

За более подробной информацией обращайтесь к Misc/SpecialBuilds.txt в дистрибутиве исходного кода Python.