Вступление¶
Интерфейс прикладного программиста для Python предоставляет программистам на C и C++ доступ к интерпретатору Python на различных уровнях. Этот API в равной степени применим и к C++, но для краткости его обычно называют Python/C API. Есть две принципиально разные причины для использования API Python/C. Первая причина заключается в написании модулей расширения для конкретных целей; это модули C, которые расширяют интерпретатор Python. Это, вероятно, наиболее распространенное использование. Вторая причина заключается в использовании Python в качестве компонента в более крупном приложении; в приложении этот метод обычно называется embedding Python.
Написание модуля расширения - относительно понятный процесс, в котором хорошо работает подход «поваренной книги». Существует несколько инструментов, которые в некоторой степени автоматизируют этот процесс. Хотя люди внедряли Python в другие приложения с самого начала его существования, процесс внедрения Python менее прост, чем написание расширения.
Многие функции API полезны независимо от того, внедряете ли вы Python или расширяете его; более того, большинству приложений, использующих Python, также потребуется предоставить пользовательское расширение, поэтому, вероятно, будет хорошей идеей ознакомиться с написанием расширения, прежде чем пытаться внедрить Python в реальное приложение.
Стандарты кодирования¶
Если вы пишете код на C для включения в CPython, вы должны следовать рекомендациям и стандартам, определенным в PEP 7. Эти рекомендации применимы независимо от версии Python, в которую вы вносите свой вклад. Соблюдение этих соглашений не обязательно для ваших собственных модулей расширения сторонних производителей, если только вы в конечном итоге не планируете использовать их в Python.
Включаемые файлы¶
Все определения функций, типов и макросов, необходимые для использования API Python/C, включены в ваш код в следующей строке:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
Это подразумевает включение следующих стандартных заголовков: <stdio.h>
, <string.h>
, <errno.h>
, <limits.h>
, <assert.h>
и <stdlib.h>
(при наличии).
Примечание
Поскольку Python может определять некоторые определения препроцессора, которые влияют на стандартные заголовки в некоторых системах, вы должны включить Python.h
перед включением любых стандартных заголовков.
Рекомендуется всегда указывать PY_SSIZE_T_CLEAN
перед включением Python.h
. Описание этого макроса приведено в Анализ аргументов и построение значений.
Все видимые пользователем имена, определенные с помощью Python.h (за исключением тех, которые определены включенными стандартными заголовками), имеют один из префиксов Py
или _Py
. Имена, начинающиеся с _Py
, предназначены для внутреннего использования в реализации Python и не должны использоваться авторами расширений. Имена элементов структуры не имеют зарезервированного префикса.
Примечание
Пользовательский код никогда не должен определять имена, начинающиеся с Py
или _Py
. Это сбивает читателя с толку и ставит под угрозу переносимость пользовательского кода на будущие версии Python, которые могут определять дополнительные имена, начинающиеся с одного из этих префиксов.
Заголовочные файлы обычно устанавливаются с помощью Python. В Unix они расположены в каталогах prefix/include/pythonversion/
и exec_prefix/include/pythonversion/
, где prefix
и exec_prefix
определяются соответствующими параметрами скрипта Python configure и версия - '%d.%d' % sys.version_info[:2]
. В Windows заголовки устанавливаются в prefix/include
, где prefix
- это каталог установки, указанный установщику.
Чтобы включить заголовки, поместите оба каталога (если они разные) в путь поиска вашего компилятора для includes. Не указывайте родительские каталоги в пути поиска, а затем используйте #include <pythonX.Y/Python.h>
; это приведет к сбоям в многоплатформенных сборках, поскольку независимые от платформы заголовки в prefix
включают в себя заголовки, зависящие от платформы, из exec_prefix
.
Пользователям C++ следует обратить внимание на то, что, хотя API полностью определен с использованием C, в заголовочных файлах точки входа должным образом указаны как extern "C"
. В результате для использования API из C++ не нужно делать ничего особенного.
Полезные макросы¶
В заголовочных файлах Python определено несколько полезных макросов. Многие из них определены ближе к тому месту, где они полезны (например, c:macro: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_ONLINE может привести к снижению производительности (например, из-за увеличения размера кода). Компилятор обычно умнее разработчика в плане анализа затрат и выгод.
Если значение Python равно built in debug mode (если определен макрос
Py_DEBUG
), макросPy_ALWAYS_INLINE
ничего не делает.Он должен быть указан перед типом возвращаемого значения функции. Использование:
static inline Py_ALWAYS_INLINE int random(void) { return 4; }
Добавлено в версии 3.11.
-
Py_CHARMASK(c)¶
Аргументом должен быть символ или целое число в диапазоне [-128, 127] или [0, 255]. Этот макрос возвращает значение
c
, приведенное к значениюunsigned char
.
-
Py_DEPRECATED(version)¶
Используйте это для устаревших объявлений. Макрос должен быть помещен перед именем символа.
Пример:
Py_DEPRECATED(3.8) PyAPI_FUNC(int) Py_OldFunction(void);
Изменено в версии 3.8: Была добавлена поддержка MSVC.
-
Py_GETENV(s)¶
Как
getenv(s)
, но возвращаетNULL
, если-E
было передано в командной строке (т.е. если задано значениеPy_IgnoreEnvironmentFlag
).
-
Py_MAX(x, y)¶
Возвращает максимальное значение между
x
иy
.Добавлено в версии 3.3.
-
Py_MEMBER_SIZE(type, member)¶
Возвращает размер структуры (
type
)member
в байтах.Добавлено в версии 3.6.
-
Py_MIN(x, y)¶
Возвращает минимальное значение между
x
иy
.Добавлено в версии 3.3.
-
Py_NO_INLINE¶
Отключите встраивание в функцию. Например, это уменьшает потребление стека C: полезно при сборках LTO+PGO, в которых много встроенного кода (см. bpo-33720).
Использование:
Py_NO_INLINE static int random(void) { return 4; }
Добавлено в версии 3.11.
-
Py_STRINGIFY(x)¶
Преобразовать
x
в строку на языке Си. Например,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
, которую можно использовать в docstrings. Если Python собран без docstrings, значение будет пустым.Используйте
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} };
Объекты, типы и количество ссылок¶
Большинство функций API Python/C имеют один или несколько аргументов, а также возвращаемое значение типа PyObject*. Этот тип является указателем на непрозрачный тип данных, представляющий произвольный объект Python. Поскольку все типы объектов Python в большинстве ситуаций обрабатываются языком Python одинаково (например, присваивания, правила области видимости и передача аргументов), вполне уместно, чтобы они были представлены одним типом C. Почти все объекты Python хранятся в куче: вы никогда не объявляете автоматическую или статическую переменную типа PyObject
, могут быть объявлены только переменные-указатели типа PyObject*. Единственным исключением являются объекты типа; поскольку они никогда не должны освобождаться, они обычно являются статическими : c:type:PyTypeObject объектами.
Все объекты Python (даже целые числа Python) имеют type и reference count. Тип объекта определяет, что это за объект (например, целое число, список или пользовательская функция; их может быть гораздо больше, как описано в Иерархия стандартных типов). Для каждого из хорошо известных типов существует макрос для проверки того, относится ли объект к этому типу; например, PyList_Check(a)
имеет значение true, если (и только если) объект, на который указывает a, является списком Python.
Количество ссылок¶
Количество ссылок важно, потому что современные компьютеры имеют конечный (и часто сильно ограниченный) объем памяти; оно подсчитывает, сколько существует различных мест, которые имеют strong reference для объекта. Таким местом может быть другой объект, или глобальная (или статическая) переменная языка Си, или локальная переменная в какой-либо функции языка Си. Когда последний strong reference объект освобождается (т.е. количество ссылок на него становится равным нулю), объект освобождается. Если он содержит ссылки на другие объекты, эти ссылки освобождаются. Эти другие объекты могут быть освобождены в свою очередь, если на них больше нет ссылок, и так далее. (Здесь возникает очевидная проблема с объектами, которые ссылаются друг на друга; на данный момент решение заключается в том, чтобы «не делать этого».)
Количество ссылок всегда управляется явно. Обычный способ - использовать макрос Py_INCREF()
, чтобы получить новую ссылку на объект (т.е. увеличить количество его ссылок на единицу), и Py_DECREF()
, чтобы освободить эту ссылку (т.е. уменьшить количество ссылок на единицу). Макрос Py_DECREF()
значительно сложнее, чем макрос incref, поскольку он должен проверять, становится ли счетчик ссылок равным нулю, а затем вызывать средство освобождения объекта. Средство освобождения - это указатель на функцию, содержащийся в структуре типа объекта. Средство освобождения, зависящее от конкретного типа, заботится об освобождении ссылок на другие объекты, содержащиеся в объекте, если это составной тип объекта, такой как список, а также выполняет любую необходимую дополнительную доработку. Нет никаких шансов, что количество ссылок может переполниться; для хранения количества ссылок используется по крайней мере столько битов, сколько имеется различных ячеек памяти в виртуальной памяти (при условии, что sizeof(Py_ssize_t) >= sizeof(void*)
). Таким образом, увеличение количества ссылок является простой операцией.
Нет необходимости сохранять значение strong reference (т.е. увеличивать количество ссылок) для каждой локальной переменной, содержащей указатель на объект. Теоретически, количество ссылок на объект увеличивается на единицу, когда переменная указывает на него, и уменьшается на единицу, когда переменная выходит за пределы области видимости. Однако эти два параметра нейтрализуют друг друга, поэтому в конечном итоге количество ссылок не изменилось. Единственная реальная причина использования счетчика ссылок заключается в том, чтобы предотвратить освобождение объекта до тех пор, пока наша переменная указывает на него. Если мы знаем, что существует по крайней мере еще одна ссылка на объект, которая существует как минимум столько же времени, сколько и наша переменная, то нет необходимости временно принимать новую strong reference (т.е. увеличивать количество ссылок). Важная ситуация, в которой это возникает, возникает в случае объектов, передаваемых в качестве аргументов функциям C в модуле расширения, которые вызываются из Python; механизм вызова гарантирует сохранение ссылки на каждый аргумент в течение всего времени вызова.
Однако распространенной ошибкой является извлечение объекта из списка и удержание его в течение некоторого времени без использования новой ссылки. Возможно, какая-либо другая операция может удалить объект из списка, освободив эту ссылку и, возможно, освободив его место. Реальная опасность заключается в том, что невинно выглядящие операции могут вызывать произвольный код на Python, который мог бы это сделать; существует путь к коду, который позволяет передавать управление обратно пользователю из a: c:func:Py_DECREF, поэтому практически любая операция потенциально опасна.
Безопасный подход заключается в том, чтобы всегда использовать универсальные операции (функции, название которых начинается с PyObject_
, PyNumber_
, PySequence_
или PyMapping_
). Эти операции всегда создают новый strong reference (т.е. увеличивают количество ссылок) объекта, который они возвращают. Это возлагает на вызывающего абонента ответственность за вызов:c:func:Py_DECREF, когда он закончит с результатом; вскоре это становится его второй натурой.
Сведения о количестве ссылок¶
Поведение функций по подсчету ссылок в API Python/C лучше всего объяснить с точки зрения владения ссылками. Право собственности относится к ссылкам, а не к объектам (объекты не являются собственностью: они всегда являются общими). «Владеть ссылкой» означает нести ответственность за вызов Py_DECREF для нее, когда ссылка больше не нужна. Право собственности также может быть передано, что означает, что код, который получает право собственности на ссылку, затем становится ответственным за ее последующее освобождение, вызывая : c:func:Py_DECREF или Py_XDECREF()
, когда она больше не нужна - или передавая эту ответственность (обычно к своему вызывающему абоненту). Когда функция передает право собственности на ссылку вызывающему объекту, считается, что вызывающий объект получает новую ссылку. Когда право собственности не передается, считается, что вызывающий объект заимствует ссылку. Ничего не нужно делать для borrowed reference.
И наоборот, когда вызывающая функция передает ссылку на объект, есть две возможности: функция крадет ссылку на объект или нет. Кража ссылки означает, что когда вы передаете ссылку функции, эта функция предполагает, что теперь она владеет этой ссылкой, и вы больше не несете за нее ответственности.
Немногие функции крадут ссылки; два заметных исключения - это : c:func: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()
(который, как оказалось, принимает точно такие же аргументы), у вас действительно есть ссылка на возвращаемый объект.
Вот пример того, как вы могли бы написать функцию, которая вычисляет сумму элементов в списке целых чисел; один раз используя : c:func:PyList_GetItem, и один раз используя:c:func: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;
}
Типы¶
Есть несколько других типов данных, которые играют важную роль в API Python/C; большинство из них - простые типы C, такие как : c:expr:int, long, double и char*. Несколько типов структур используются для описания статических таблиц, используемых для перечисления функций, экспортируемых модулем, или атрибутов данных нового типа объекта, а другой тип используется для описания значения комплексного числа. Они будут рассмотрены вместе с функциями, которые их используют.
-
type Py_ssize_t¶
- Part of the Стабильный ABI.
Целочисленный тип со знаком, такой как
sizeof(Py_ssize_t) == sizeof(size_t)
. В C99 это не определено напрямую (size_t - это целочисленный тип без знака). Подробности смотрите в PEP 353.PY_SSIZE_T_MAX
- это наибольшее положительное значение типаPy_ssize_t
.
Исключения¶
Программисту на Python нужно иметь дело с исключениями только в том случае, если требуется специальная обработка ошибок; необработанные исключения автоматически передаются вызывающему объекту, затем вызывающему объекту вызывающего объекта и так далее, пока они не достигнут интерпретатора верхнего уровня, где о них сообщается пользователю в сопровождении обратной трассировки стека.
Однако для программистов на C проверка ошибок всегда должна быть явной. Все функции в Python/C API могут вызывать исключения, если в документации к функции не указано иное. Как правило, когда функция обнаруживает ошибку, она устанавливает исключение, удаляет все ссылки на объекты, которыми она владеет, и возвращает индикатор ошибки. Если не указано иное, этот индикатор имеет значение NULL
или -1
, в зависимости от типа возвращаемого значения функции. Некоторые функции возвращают логическое значение true/false, при этом значение false указывает на ошибку. Очень немногие функции не возвращают явный индикатор ошибки или имеют неоднозначное возвращаемое значение и требуют явного тестирования на наличие ошибок с помощью PyErr_Occurred()
. Эти исключения всегда четко документируются.
Состояние исключения сохраняется в хранилище для каждого потока (это эквивалентно использованию глобального хранилища в непоточном приложении). Поток может находиться в одном из двух состояний: произошло исключение или нет. Для проверки этого можно использовать функцию PyErr_Occurred()
: она возвращает заимствованную ссылку на объект типа exception, когда возникает исключение, и 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
Вот соответствующий код на языке Си во всей его красе:
int
incr_item(PyObject *dict, PyObject *key)
{
/* Objects all initialized to NULL for Py_XDECREF */
PyObject *item = NULL, *const_one = NULL, *incremented_item = NULL;
int rv = -1; /* Return value initialized to -1 (failure) */
item = PyObject_GetItem(dict, key);
if (item == NULL) {
/* Handle KeyError only: */
if (!PyErr_ExceptionMatches(PyExc_KeyError))
goto error;
/* Clear the error and use zero: */
PyErr_Clear();
item = PyLong_FromLong(0L);
if (item == NULL)
goto error;
}
const_one = PyLong_FromLong(1L);
if (const_one == NULL)
goto error;
incremented_item = PyNumber_Add(item, const_one);
if (incremented_item == NULL)
goto error;
if (PyObject_SetItem(dict, key, incremented_item) < 0)
goto error;
rv = 0; /* Success */
/* Continue with cleanup code */
error:
/* Cleanup code, shared by success and failure path */
/* Use Py_XDECREF() to ignore NULL references */
Py_XDECREF(item);
Py_XDECREF(const_one);
Py_XDECREF(incremented_item);
return rv; /* -1 for error, 0 for success */
}
Этот пример представляет собой одобренное использование инструкции goto
в C! Это иллюстрирует использование PyErr_ExceptionMatches()
и PyErr_Clear()
для обработки конкретных исключений, а также использование Py_XDECREF()
для удаления принадлежащих ссылок, которые могут быть NULL
(обратите внимание на 'X'
в названии; Py_DECREF()
приведет к сбою при столкновении со ссылкой на NULL
). Важно, чтобы переменные, используемые для хранения принадлежащих ссылок, были инициализированы значением NULL
, чтобы это сработало; аналогично, предлагаемое возвращаемое значение инициализируется значением -1
(ошибка) и устанавливается в значение success только после успешного выполнения последнего вызова.
Встраивание Python¶
Единственная важная задача, о которой приходится беспокоиться только разработчикам приложений (в отличие от разработчиков расширений) интерпретатора Python, - это инициализация и, возможно, завершение работы интерпретатора Python. Большая часть функциональных возможностей интерпретатора может быть использована только после его инициализации.
Основной функцией инициализации является : c:func:Py_Initialize. Она инициализирует таблицу загруженных модулей и создает основные модули builtins
, __main__
, и sys
. Он также инициализирует путь поиска модуля (sys.path
).
Py_Initialize()
не задает «список аргументов скрипта» (sys.argv
). Если эта переменная необходима для кода на Python, который будет выполнен позже, необходимо установить значения PyConfig.argv
и PyConfig.parse_argv
: смотрите Python Initialization Configuration.
В большинстве систем (в частности, в Unix и Windows, хотя детали немного отличаются) Py_Initialize()
вычисляет путь поиска модуля на основе наилучшего предположения о местоположении стандартного исполняемого файла интерпретатора Python, предполагая, что библиотека Python находится в определенном месте относительно исполняемого файла интерпретатора Python. В частности, он ищет каталог с именем lib/pythonX.Y
относительно родительского каталога, в котором исполняемый файл с именем python
найден в пути поиска команды оболочки (переменная окружения PATH
).
Например, если исполняемый файл Python находится в /usr/local/bin/python
, то будет предполагаться, что библиотеки находятся в /usr/local/lib/pythonX.Y
. (На самом деле, этот конкретный путь также является «запасным» расположением, используемым, когда по PATH
не найден исполняемый файл с именем python
.) Пользователь может переопределить это поведение, установив переменную окружения PYTHONHOME
, или вставить дополнительные каталоги перед стандартным путем, установив PYTHONPATH
.
Встраиваемое приложение может управлять поиском, вызывая Py_SetProgramName(file)
перед вызовом Py_Initialize()
. Обратите внимание, что PYTHONHOME
по-прежнему переопределяет это значение, а PYTHONPATH
по-прежнему вставляется перед стандартным путем. Приложение, требующее полного контроля, должно предоставлять свою собственную реализацию : c:func:Py_GetPath, Py_GetPrefix()
, Py_GetExecPrefix()
и Py_GetProgramFullPath()
(все они определены в Modules/getpath.c
).
Иногда желательно «неинициализировать» Python. Например, приложение может захотеть начать все сначала (выполнить другой вызов Py_Initialize()
) или приложение просто завершает работу с использованием Python и хочет освободить память, выделенную Python. Это можно сделать, вызвав Py_FinalizeEx()
. Функция Py_IsInitialized()
возвращает значение true, если Python в данный момент находится в инициализированном состоянии. Более подробная информация об этих функциях приведена в следующей главе. Обратите внимание, что : c:func:Py_FinalizeEx не освобождает всю память, выделенную интерпретатором Python, например память, выделенная модулями расширения, в настоящее время не может быть освобождена.
Отладочные сборки¶
В Python можно встроить несколько макросов, чтобы включить дополнительные проверки интерпретатора и модулей расширения. Эти проверки, как правило, увеличивают нагрузку на среду выполнения, поэтому по умолчанию они не включены.
Полный список различных типов отладочных сборок находится в файле Misc/SpecialBuilds.txt
в дистрибутиве исходного кода Python. Доступны сборки, которые поддерживают отслеживание количества ссылок, отладку распределителя памяти или низкоуровневое профилирование основного цикла интерпретатора. В оставшейся части этого раздела будут описаны только наиболее часто используемые сборки.
-
Py_DEBUG¶
Компиляция интерпретатора с использованием определенного макроса Py_DEBUG
приводит к тому, что обычно подразумевается под a debug build of Python. Py_DEBUG
включен в сборке Unix путем добавления --with-pydebug
к ./configure
команда. Это также подразумевается наличием макроса, не относящегося к Python _DEBUG
. Когда в сборке Unix включен параметр Py_DEBUG
, оптимизация компилятора отключена.
В дополнение к описанной ниже отладке подсчета ссылок выполняются дополнительные проверки, см. Python Debug Build.
Определение Py_TRACE_REFS
позволяет отслеживать ссылки (см. configure --with-trace-refs option
). При определении поддерживается циклический двусвязный список активных объектов путем добавления двух дополнительных полей к каждому PyObject
. Также отслеживается общее распределение ресурсов. При выходе выводятся все существующие ссылки. (В интерактивном режиме это происходит после каждой инструкции, выполняемой интерпретатором).
Пожалуйста, обратитесь к Misc/SpecialBuilds.txt
в исходном коде Python для получения более подробной информации.