Введение

Интерфейс прикладного программиста для 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, а 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++ не нужно делать ничего особенного.

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

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

Py_UNREACHABLE()

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

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

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

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

Добавлено в версии 3.7.

Py_ABS(x)

Возвращает абсолютное значение x.

Добавлено в версии 3.3.

Py_MIN(x, y)

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

Добавлено в версии 3.3.

Py_MAX(x, y)

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

Добавлено в версии 3.3.

Py_STRINGIFY(x)

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

Добавлено в версии 3.4.

Py_MEMBER_SIZE(type, member)

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

Добавлено в версии 3.6.

Py_CHARMASK(c)

Аргументом должен быть символ или целое число в диапазоне [-128, 127] или [0, 255]. Этот макрос возвращает c, приведенное к unsigned char.

Py_GETENV(s)

Аналогично getenv(s), но возвращает NULL, если -E было передано в командной строке (т.е. если установлено Py_IgnoreEnvironmentFlag).

Py_UNUSED(arg)

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

Добавлено в версии 3.4.

Py_DEPRECATED(version)

Используйте его для устаревших объявлений. Макрос должен быть помещен перед именем символа.

Пример:

Py_DEPRECATED(3.8) PyAPI_FUNC(int) Py_OldFunction(void);

Изменено в версии 3.8: Добавлена поддержка MSVC.

PyDoc_STRVAR(name, str)

Создает переменную с именем name, которая может быть использована в docstrings. Если Python собран без docstrings, значение будет пустым.

Используйте PyDoc_STRVAR для docstrings, чтобы поддерживать сборку Python без docstrings, как указано в 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)

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

Используйте 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}
};

Объекты, типы и количество ссылок

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

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

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

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

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

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

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

Безопасный подход - всегда использовать общие операции (функции, имя которых начинается с PyObject_, PyNumber_, PySequence_ или PyMapping_). Эти операции всегда увеличивают счетчик ссылок возвращаемого объекта. Это возлагает на вызывающего ответственность за вызов 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
Part of the Stable 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 (неудача) и устанавливается в успех только после успешного завершения последнего вызова.

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

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

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

Py_Initialize() не устанавливает «список аргументов сценария» (sys.argv). Если эта переменная нужна коду Python, который будет выполняться позже, она должна быть установлена явным образом вызовом PySys_SetArgvEx(argc, argv, updatepath) после вызова Py_Initialize().

В большинстве систем (в частности, в 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, например, память, выделенная модулями расширения, в настоящее время не может быть освобождена.

Отладка сборки

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

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

Компиляция интерпретатора с определенным макросом 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). При определении :c ведется круговой двусвязный список активных объектов путем добавления двух дополнительных полей к каждому PyObject. Также отслеживается общее распределение. При выходе все существующие ссылки выводятся на печать. (В интерактивном режиме это происходит после каждого оператора, выполняемого интерпретатором).

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

Вернуться на верх