Документация Python неофициальный перевод
Содержание страницы

ВведениеIntroduction

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

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

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

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

При написании кода на C для включения в CPython необходимо следовать рекомендациям и стандартам, определённым в PEP 7. Эти рекомендации действуют независимо от версии Python, в которую вносится вклад. Следование этим соглашениям не обязательно для собственных сторонних модулей расширения, если не планируется в конечном счёте передать их в Python.

Заголовочные файлыInclude Files

Все определения функций, типов и макросов, необходимые для использования Python/C API, включаются в код с помощью следующей строки:

#define PY_SSIZE_T_CLEAN
#include <Python.h>

Это подразумевает включение следующих стандартных заголовочных файлов: <stdio.h>, <string.h>, <errno.h>, <limits.h>, <assert.h> и <stdlib.h> (если доступны).

Примечание

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

Рекомендуется всегда определять PY_SSIZE_T_CLEAN перед включением Python.h. См. Разбор аргументов и создание значений для описания этого макроса.

Все видимые пользователю имена, определённые Python.h (кроме тех, что определены включёнными стандартными заголовками), имеют один из префиксов Py или _Py. Имена, начинающиеся с _Py, предназначены для внутреннего использования реализацией Python и не должны использоваться разработчиками расширений. Имена членов структур не имеют зарезервированного префикса.

Примечание

Пользовательский код никогда не должен определять имена, начинающиеся с Py или _Py. Это сбивает с толку читателя и ставит под угрозу переносимость пользовательского кода на будущие версии Python, которые могут определять дополнительные имена, начинающиеся с одного из этих префиксов.

Заголовочные файлы обычно устанавливаются вместе с Python. В Unix они находятся в каталогах prefix/include/pythonversion/ и exec_prefix/include/pythonversion/, где prefix и exec_prefix определяются соответствующими параметрами сценария configure Python, а version'%d.%d' % sys.version_info[:2]. В Windows заголовочные файлы устанавливаются в prefix/include, где prefix – каталог установки, указанный в программе установки.

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

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

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

В заголовочных файлах 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.12.

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.12.

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}
};

Объекты, типы и счетчики ссылокObjects, Types and Reference Counts

Большинство функций Python/C API принимают один или несколько аргументов и возвращают значение типа PyObject*. Этот тип является указателем на непрозрачный тип данных представляющий произвольный объект Python. Поскольку все типы объектов Python обрабатываются языком Python одинаково в большинстве ситуаций (например, присваивание, правила области видимости, передача аргументов), вполне естественно, что они должны быть представлены единым типом C. Почти все объекты Python находятся в куче: никогда не объявляется автоматическая или статическая переменная типа PyObject, можно объявлять только переменные-указатели типа PyObject* объявлена. Единственное исключение – объекты типов; поскольку они никогда не должны освобождаться, они обычно являются статическими PyTypeObject объектами.

Все объекты Python (даже целые числа Python) имеют тип и счетчик ссылок. Тип объекта определяет, что это за объект (например, целое число, список или пользовательская функция; существует гораздо больше типов, как описано в Стандартная иерархия типов). Для каждого из известных типов существует макрос, проверяющий, является ли объект объектом этого типа; например, PyList_Check(a) истинно тогда и только тогда, когда объект, на который указывает a, является списком Python.

Счетчики ссылокReference Counts

Счётчик ссылок важен, потому что современные компьютеры имеют конечный (и часто очень ограниченный) объём памяти; он подсчитывает, сколько различных мест имеют сильную ссылку на объект. Таким местом может быть другой объект, глобальная (или статическая) переменная 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(), когда он закончит работу с результатом; это быстро входит в привычку.

Подробности о счетчиках ссылокReference Count Details

Поведение функций 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; /* Не список */
    for (i = 0; i < n; i++) {
        item = PyList_GetItem(list, i); /* Не может завершиться ошибкой */
        if (!PyLong_Check(item)) continue; /* Пропустить нецелые значения */
        value = PyLong_AsLong(item);
        if (value == -1 && PyErr_Occurred())
            /* Целое число слишком велико для C long, выход */
            return -1;
        total += value;
    }
    return total;
}
long
sum_sequence(PyObject *sequence)
{
    Py_ssize_t i, n;
    long total = 0, value;
    PyObject *item;
    n = PySequence_Length(sequence);
    if (n < 0)
        return -1; /* Не имеет длины */
    for (i = 0; i < n; i++) {
        item = PySequence_GetItem(sequence, i);
        if (item == NULL)
            return -1; /* Не последовательность или другая ошибка */
        if (PyLong_Check(item)) {
            value = PyLong_AsLong(item);
            Py_DECREF(item);
            if (value == -1 && PyErr_Occurred())
                /* Целое число слишком велико для C long, выход */
                return -1;
            total += value;
        }
        else {
            Py_DECREF(item); /* Отказ от владения ссылкой */
        }
    }
    return total;
}

ТипыTypes

Существует ещё несколько типов данных, играющих важную роль в Python/C API; большинство из них – простые типы C, такие как int, long, double и char*. Некоторые структурные типы используются для описания статических таблиц, в которых перечисляются функции, экспортируемые модулем, или атрибуты данных нового типа объекта, а другой тип используется для описания значения комплексного числа. Они будут рассмотрены вместе с функциями, которые их используют.

type Py_ssize_t
Часть Stable ABI.

Знаковый целочисленный тип, такой что sizeof(Py_ssize_t) == sizeof(size_t). C99 не определяет такой тип напрямую (size_t – это беззнаковый целочисленный тип). Подробнее см. PEP 353. PY_SSIZE_T_MAX – это наибольшее положительное значение типа Py_ssize_t.

ИсключенияExceptions

Программисту на 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 представляют последнее исключение, обрабатываемое оператором 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)
{
    /* Все объекты инициализированы в NULL для Py_XDECREF */
    PyObject *item = NULL, *const_one = NULL, *incremented_item = NULL;
    int rv = -1; /* Возвращаемое значение инициализировано как -1 (ошибка) */

    item = PyObject_GetItem(dict, key);
    if (item == NULL) {
        /* Обрабатывать только KeyError: */
        if (!PyErr_ExceptionMatches(PyExc_KeyError))
            goto error;

        /* Очистить ошибку и использовать ноль: */
        PyErr_Clear();
        item = PyLong_FromLong(0L);
        if (item == NULL)
            goto error;
    }
    const_one = PyLong_FromLong(1L);
    if (const_one == NULL)
        goto error;

    incremented_item = PyNumber_Add(item, const_one);
    if (incremented_item == NULL)
        goto error;

    if (PyObject_SetItem(dict, key, incremented_item) < 0)
        goto error;
    rv = 0; /* Успех */
    /* Продолжить с кодом очистки */

 error:
    /* Код очистки, общий для путей успеха и ошибки */

    /* Используйте Py_XDECREF() для игнорирования NULL-ссылок */
    Py_XDECREF(item);
    Py_XDECREF(const_one);
    Py_XDECREF(incremented_item);

    return rv; /* -1 для ошибки, 0 для успеха */
}

Этот пример представляет собой одобренное использование оператора goto в C! Он иллюстрирует использование PyErr_ExceptionMatches() и PyErr_Clear() для обработки конкретных исключений, а также использование Py_XDECREF() для освобождения принадлежащих ссылок, которые могут быть NULL (обратите внимание на 'X' в имени; Py_DECREF() аварийно завершится при столкновении с NULL ссылкой). Важно, чтобы переменные, используемые для хранения принадлежащих ссылок, были инициализированы значением NULL для корректной работы; аналогично, предлагаемое возвращаемое значение инициализируется как -1 (неудача) и устанавливается в успех только после того, как последний вызов завершится успешно.

Встраивание PythonEmbedding 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. (Фактически, этот конкретный путь также является «запасным» местоположением, используемым, когда исполняемый файл с именем python не найден вдоль PATH.) Пользователь может переопределить это поведение, установив переменную окружения PYTHONHOME, или вставить дополнительные каталоги в начало стандартного пути, установив PYTHONPATH.

Встраивающее приложение может управлять поиском, вызвав Py_SetProgramName(file) перед вызовом Py_Initialize(). Обратите внимание, что PYTHONHOME по-прежнему переопределяет это, а PYTHONPATH всё ещё вставляется перед стандартным путём. Приложение, требующее полного контроля, должно предоставить собственную реализацию Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix() и Py_GetProgramFullPath() (все они определены в Modules/getpath.c).

Иногда бывает желательно «деинициализировать» Python. Например, приложение может захотеть начать заново (сделать ещё один вызов Py_Initialize()) или просто завершить использование Python и освободить память, выделенную Python. Это можно сделать, вызвав Py_FinalizeEx(). Функция Py_IsInitialized() возвращает true, если Python в настоящее время находится в инициализированном состоянии. Дополнительная информация об этих функциях приведена в следующей главе. Обратите внимание, что Py_FinalizeEx() не освобождает всю память, выделенную интерпретатором Python, например, память, выделенная модулями расширения, в настоящее время не может быть освобождена.

Отладочные сборкиDebugging Builds

Python может быть собран с несколькими макросами для включения дополнительных проверок интерпретатора и модулей расширения. Эти проверки, как правило, добавляют значительные накладные расходы во время выполнения, поэтому они не включены по умолчанию.

Полный список различных типов отладочных сборок находится в файле Misc/SpecialBuilds.txt в дистрибутиве исходного кода Python. Доступны сборки, поддерживающие трассировку счётчиков ссылок, отладку распределителя памяти или низкоуровневое профилирование основного цикла интерпретатора. В оставшейся части этого раздела будут описаны только наиболее часто используемые сборки.

Py_DEBUG

Компиляция интерпретатора с определённым макросом Py_DEBUG даёт то, что обычно называют отладочной сборкой Python. Py_DEBUG включается в сборке Unix добавлением --with-pydebug к команде ./configure. Оно также подразумевается наличием неспецифичного для Python макроса _DEBUG. Когда Py_DEBUG включён в сборке Unix, оптимизация компилятора отключается.

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

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

См. Misc/SpecialBuilds.txt в дистрибутиве исходных текстов Python для получения более подробной информации.