Spec-Zone.ru › Python 3.8

Введение

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

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

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

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

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

Файлы заголовков

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

#define PY_SSIZE_T_CLEAN
#include <Python.h>

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

Примечание

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

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

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

Примечание

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

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

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

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

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

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

Py_UNREACHABLE()

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

Добавлено в версии 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 в строку C. Например, 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, которую можно использовать в строках документации. Если Python построен без строк документации, значение будет пустым.

Используйте PyDoc_STRVAR для строк документации, чтобы поддерживать сборку Python без строк документации, как указано в PEP 7.

Пример:

PyDoc_STRVAR(pop_doc, "Remove and return the rightmost element.");

static PyMethodDef deque_methods[] = {
    // ...
    {"pop", (PyCFunction)deque_pop, METH_NOARGS, pop_doc},
    // ...
}
PyDoc_STR(str)

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

Используйте PyDoc_STR при указании строк документации для поддержки сборки Python без строк документации, как указано в PEP 7.

Пример:

static PyMethodDef pysqlite_row_methods[] = {
    {"keys", (PyCFunction)pysqlite_row_keys, METH_NOARGS,
        PyDoc_STR("Returns the keys of the row.")},
    {NULL, NULL}
};

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

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

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

END_OF_DOCUMENT_MARKER

Счётчики ссылок

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

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

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

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

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

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

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

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

Несколько функций захватывают ссылки; два заметных исключения — PyList_SetItem() и PyTuple_SetItem(), которые захватывают ссылку на элемент (но не на кортеж или список, в который помещается элемент!). Эти функции были разработаны для захвата ссылки из-за распространённого способа заполнения кортежа или списка вновь созданными объектами; например, код для создания кортежа (1, 2, "three") может выглядеть так (на данный момент мы игнорируем обработку ошибок; лучший способ кодирования показан ниже):

PyObject *t;

t = PyTuple_New(3);
PyTuple_SetItem(t, 0, PyLong_FromLong(1L));
PyTuple_SetItem(t, 1, PyLong_FromLong(2L));
PyTuple_SetItem(t, 2, PyUnicode_FromString("three"));

Здесь PyLong_FromLong() возвращает новую ссылку, которая немедленно захватывается PyTuple_SetItem(). Если вы хотите продолжить использование объекта, хотя ссылка на него будет захвачена, используйте Py_INCREF() для получения ещё одной ссылки перед вызовом функции захвата ссылки.

Кстати, PyTuple_SetItem() — единственный способ установить элементы кортежа; PySequence_SetItem() и PyObject_SetItem() отказываются делать это, так как кортежи — неизменяемый тип данных. Вы должны использовать только PyTuple_SetItem() для кортежей, которые вы создаёте сами.

Аналогичный код для заполнения списка можно написать с использованием PyList_New() и PyList_SetItem().

Однако на практике вы редко будете использовать эти способы создания и заполнения кортежа или списка. Существует общая функция Py_BuildValue(), которая может создавать большинство распространённых объектов из C-значений, используя строку формата. Например, два блока кода выше можно заменить следующим (который также обрабатывает проверку ошибок):

PyObject *tuple, *list;

tuple = Py_BuildValue("(iis)", 1, 2, "three");
list = Py_BuildValue("[iis]", 1, 2, "three");

Гораздо чаще используется PyObject_SetItem() и аналогичные функции с элементами, для которых вы лишь заимствуете ссылки, например, аргументы, переданные в функцию, которую вы пишете. В этом случае их поведение относительно счётчиков ссылок более разумное, так как вам не нужно увеличивать счётчик ссылок, чтобы передать ссылку («чтобы она была захвачена»). Например, эта функция устанавливает все элементы списка (на самом деле любого изменяемого последовательности) на заданный элемент:

int
set_all(PyObject *target, PyObject *item)
{
    Py_ssize_t i, n;

    n = PyObject_Length(target);
    if (n < 0)
        return -1;
    for (i = 0; i < n; i++) {
        PyObject *index = PyLong_FromSsize_t(i);
        if (!index)
            return -1;
        if (PyObject_SetItem(target, index, item) < 0) {
            Py_DECREF(index);
            return -1;
        }
        Py_DECREF(index);
    }
    return 0;
}

Ситуация немного отличается для значений, возвращаемых функциями. В то время как передача ссылки большинству функций не меняет ваши обязанности по владению этой ссылкой, многие функции, возвращающие ссылку на объект, предоставляют вам владение ссылкой. Причина проста: во многих случаях возвращаемый объект создаётся на лету, и полученная вами ссылка — единственная ссылка на объект. Поэтому общие функции, возвращающие ссылки на объекты, такие как PyObject_GetItem() и PySequence_GetItem(), всегда возвращают новую ссылку (вызывающая функция становится владельцем ссылки).

Важно понимать, что владение ссылкой, возвращаемой функцией, зависит только от вызываемой функции — тип возвращаемого объекта (тип объекта, переданного в функцию) не имеет значения! Таким образом, если вы извлекаете элемент из списка с помощью PyList_GetItem(), вы не владеете ссылкой — но если вы получаете тот же элемент из того же списка с помощью PySequence_GetItem() (который принимает точно те же аргументы), вы владеете ссылкой на возвращённый объект.

Вот пример того, как можно написать функцию, вычисляющую сумму элементов в списке целых чисел; один раз используя PyList_GetItem(), и один раз используя PySequence_GetItem().

long
sum_list(PyObject *list)
{
    Py_ssize_t i, n;
    long total = 0, value;
    PyObject *item;

    n = PyList_Size(list);
    if (n < 0)
        return -1; /* Not a list */
    for (i = 0; i < n; i++) {
        item = PyList_GetItem(list, i); /* Can't fail */
        if (!PyLong_Check(item)) continue; /* Skip non-integers */
        value = PyLong_AsLong(item);
        if (value == -1 && PyErr_Occurred())
            /* Integer too big to fit in a C long, bail out */
            return -1;
        total += value;
    }
    return total;
}
long
sum_sequence(PyObject *sequence)
{
    Py_ssize_t i, n;
    long total = 0, value;
    PyObject *item;
    n = PySequence_Length(sequence);
    if (n < 0)
        return -1; /* Has no length */
    for (i = 0; i < n; i++) {
        item = PySequence_GetItem(sequence, i);
        if (item == NULL)
            return -1; /* Not a sequence, or other failure */
        if (PyLong_Check(item)) {
            value = PyLong_AsLong(item);
            Py_DECREF(item);
            if (value == -1 && PyErr_Occurred())
                /* Integer too big to fit in a C long, bail out */
                return -1;
            total += value;
        }
        else {
            Py_DECREF(item); /* Discard reference ownership */
        }
    }
    return total;
}

Типы

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

Исключения

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

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

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

Полное состояние исключения состоит из трёх объектов (все из которых могут быть NULL): тип исключения, соответствующее значение исключения и отслеживание. Они имеют то же значение, что и результат Python от sys.exc_info(); однако они не идентичны: объекты Python представляют последнее исключение, обрабатываемое оператором Python try … except, в то время как состояние исключения на уровне C существует только во время передачи исключения между функциями C до тех пор, пока оно не достигнет основного цикла интерпретатора байт-кода Python, который позаботится о его передаче sys.exc_info() и др.

Обратите внимание, что начиная с Python 1.5, предпочтительный, безопасный для потоков способ доступа к состоянию исключения из кода Python — это вызов функции sys.exc_info(), которая возвращает состояние исключения на нить для кода Python. Кроме того, семантика обоих способов доступа к состоянию исключения изменилась таким образом, что функция, которая перехватывает исключение, сохранит и восстановит состояние исключения своей нити, чтобы сохранить состояние исключения своего вызывающего объекта. Это предотвращает распространённые ошибки в коде обработки исключений, вызванные, казалось бы, безобидной функцией, перезаписывающей обрабатываемое исключение; это также уменьшает часто нежелательное расширение времени жизни объектов, на которые ссылаются кадровые элементы стека в отслеживании.

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

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

def incr_item(dict, key):
    try:
        item = dict[key]
    except KeyError:
        item = 0
    dict[key] = item + 1

Вот соответствующий код C, во всей его красе:

int
incr_item(PyObject *dict, PyObject *key)
{
    /* Objects all initialized to NULL for Py_XDECREF */
    PyObject *item = NULL, *const_one = NULL, *incremented_item = NULL;
    int rv = -1; /* Return value initialized to -1 (failure) */

    item = PyObject_GetItem(dict, key);
    if (item == NULL) {
        /* Handle KeyError only: */
        if (!PyErr_ExceptionMatches(PyExc_KeyError))
            goto error;

        /* Clear the error and use zero: */
        PyErr_Clear();
        item = PyLong_FromLong(0L);
        if (item == NULL)
            goto error;
    }
    const_one = PyLong_FromLong(1L);
    if (const_one == NULL)
        goto error;

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

    if (PyObject_SetItem(dict, key, incremented_item) < 0)
        goto error;
    rv = 0; /* Success */
    /* Continue with cleanup code */

 error:
    /* Cleanup code, shared by success and failure path */

    /* Use Py_XDECREF() to ignore NULL references */
    Py_XDECREF(item);
    Py_XDECREF(const_one);
    Py_XDECREF(incremented_item);

    return rv; /* -1 for error, 0 for success */
}

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

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

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

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

Py_Initialize() не устанавливает «список аргументов скрипта» (sys.argv). Если эта переменная нужна коду Python, который будет выполняться позже, её нужно явно установить вызовом 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 обычно приводит к «отладочной сборке» Python. Py_DEBUG включено в сборке для Unix путем добавления --with-pydebug к команде ./configure. Оно также подразумевается наличием неспецифичного для Python макроса _DEBUG. Когда Py_DEBUG включено в сборке для Unix, оптимизация компилятора отключена.

В дополнение к отладке ссылок, описанной ниже, выполняются следующие дополнительные проверки:

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

Возможно, есть дополнительные проверки, не упомянутые здесь.

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

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

© 2001–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.8/c-api/intro.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API