intro.md
1> **Источник:** https://python-all.ru/3.9/c-api/intro.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Введение89Интерфейс прикладного программирования Python предоставляет программистам на C и C++ доступ к интерпретатору Python на различных уровнях. API одинаково пригоден для использования из C++, но для краткости его обычно называют Python/C API. Есть две принципиально разные причины для использования Python/C API. Первая – написание *модулей расширения* для конкретных целей; это модули на C, которые расширяют интерпретатор Python. Вероятно, это наиболее распространённое применение. Вторая – использование Python как компонента в более крупном приложении; этот метод обычно называют *встраиванием* Python в приложение.1011Написание модуля расширения – относительно хорошо понятный процесс, где хорошо работает подход «кулинарной книги» (cookbook). Существует несколько инструментов, которые в некоторой степени автоматизируют этот процесс. Хотя Python встраивали в другие приложения с самого начала его существования, процесс встраивания Python менее прямолинейный, чем написание расширения.1213Многие функции API полезны независимо от того, встраивается Python или расширяется; более того, большинство приложений, встраивающих Python, также должны предоставлять собственное расширение, поэтому, вероятно, стоит ознакомиться с написанием расширения, прежде чем пытаться встроить Python в реальное приложение.1415## Стандарты кодирования1617При написании кода на C для включения в CPython **необходимо** следовать рекомендациям и стандартам, определённым в [**PEP 7**](https://python-all.ru/3.9/c-api/intro.html). Эти рекомендации действуют независимо от версии Python, в которую вносится вклад. Следование этим соглашениям не обязательно для собственных сторонних модулей расширения, если не планируется в конечном счёте передать их в Python.1819## Заголовочные файлы2021Все определения функций, типов и макросов, необходимые для использования Python/C API, включаются в код с помощью следующей строки:2223```c24#define PY_SSIZE_T_CLEAN25#include <Python.h>26```2728Это подразумевает включение следующих стандартных заголовочных файлов: `<stdio.h>`, `<string.h>`, `<errno.h>`, `<limits.h>`, `<assert.h>` и `<stdlib.h>` (если доступны).2930> **Примечание**31>32> Поскольку Python может определять некоторые директивы препроцессора, которые влияют на стандартные заголовочные файлы в некоторых системах, *необходимо* включать `Python.h` до того, как будут включены любые стандартные заголовочные файлы.33>34> Рекомендуется всегда определять `PY_SSIZE_T_CLEAN` перед включением `Python.h`. См. [Разбор аргументов и создание значений](https://python-all.ru/3.9/c-api/arg.html#arg-parsing) для описания этого макроса.3536Все видимые пользователю имена, определённые Python.h (кроме тех, что определены включёнными стандартными заголовками), имеют один из префиксов `Py` или `_Py`. Имена, начинающиеся с `_Py`, предназначены для внутреннего использования реализацией Python и не должны использоваться разработчиками расширений. Имена членов структур не имеют зарезервированного префикса.3738> **Примечание**39>40> Пользовательский код никогда не должен определять имена, начинающиеся с `Py` или `_Py`. Это сбивает с толку читателя и ставит под угрозу переносимость пользовательского кода на будущие версии Python, которые могут определять дополнительные имена, начинающиеся с одного из этих префиксов.4142Заголовочные файлы обычно устанавливаются вместе с Python. В Unix они находятся в каталогах `prefix/include/pythonversion/` и `exec_prefix/include/pythonversion/`, где `prefix` и `exec_prefix` определяются соответствующими параметрами сценария **configure**, а *version* – это `'%d.%d' % sys.version_info[:2]`. В Windows заголовки устанавливаются в `prefix/include`, где `prefix` – это каталог установки, указанный в инсталляторе.4344Чтобы подключить заголовочные файлы, поместите оба каталога (если они разные) в путь поиска include вашего компилятора. *Не* помещайте родительские каталоги в путь поиска и затем используйте `#include <pythonX.Y/Python.h>`; это нарушит сборку на нескольких платформах, поскольку независимые от платформы заголовки в `prefix` включают платформозависимые заголовки из `exec_prefix`.4546Пользователям C++ следует отметить, что, хотя API полностью определён с использованием C, заголовочные файлы правильно объявляют точки входа как `extern "C"`. В результате нет необходимости делать что-то особенное для использования API из C++.4748## Полезные макросы4950В заголовочных файлах Python определено несколько полезных макросов. Многие из них находятся рядом с местом применения (например, [`Py_RETURN_NONE`](https://python-all.ru/3.9/c-api/none.html#c.Py_RETURN_NONE)). Макросы более общего назначения приведены здесь. Это не обязательно полный перечень.5152**`Py_UNREACHABLE`()**5354Используйте этот макрос, когда есть путь выполнения, который по замыслу не может быть достигнут. Например, в ветке `default:` оператора `switch`, для которого все возможные значения покрыты ветками `case`. Используйте его в местах, где вы могли бы попытаться поместить вызов `assert(0)` или `abort()`.5556В релизном режиме макрос помогает компилятору оптимизировать код и избегает предупреждения о недостижимом коде. Например, макрос реализован с помощью `__builtin_unreachable()` в GCC в релизном режиме.5758Один из случаев использования `Py_UNREACHABLE()` – после вызова функции, которая никогда не возвращает управление, но не объявлена как `_Py_NO_RETURN`.5960Если путь выполнения является крайне маловероятным, но может быть достигнут в исключительных случаях, этот макрос использовать нельзя. Например, при нехватке памяти или если системный вызов возвращает значение за пределами ожидаемого диапазона. В этом случае лучше сообщить об ошибке вызывающему коду. Если ошибка не может быть сообщена вызывающему коду, можно использовать [`Py_FatalError()`](https://python-all.ru/3.9/c-api/sys.html#c.Py_FatalError).6162Добавлено в версии 3.7.6364**`Py_ABS`(x)**6566Возвращает абсолютное значение `x`.6768Новое в версии 3.3.6970**`Py_MIN`(x, y)**7172Возвращает минимальное значение между `x` и `y`.7374Новое в версии 3.3.7576**`Py_MAX`(x, y)**7778Возвращает максимум из `x` и `y`.7980Новое в версии 3.3.8182**`Py_STRINGIFY`(x)**8384Преобразует `x` в C-строку. Например, `Py_STRINGIFY(123)` возвращает `"123"`.8586Новое в версии 3.4.8788**`Py_MEMBER_SIZE`(type, member)**8990Возвращает размер структуры (`type`) `member` в байтах.9192Новое в версии 3.6.9394**`Py_CHARMASK`(c)**9596Аргумент должен быть символом или целым числом в диапазоне \[-128, 127\] или \[0, 255\]. Этот макрос возвращает `c`, приведённый к `unsigned char`.9798**`Py_GETENV`(s)**99100Как `getenv(s)`, но возвращает `NULL`, если [`-E`](https://python-all.ru/3.9/using/cmdline.html#cmdoption-e) было передано в командной строке (то есть если установлена `Py_IgnoreEnvironmentFlag`).101102**`Py_UNUSED`(arg)**103104Используется для неиспользуемых аргументов в определении функции, чтобы подавить предупреждения компилятора. Пример: `int func(int a, int Py_UNUSED(b)) { return a; }`.105106Новое в версии 3.4.107108**`Py_DEPRECATED`(version)**109110Используется для объявлений устаревших элементов. Макрос должен располагаться перед именем символа.111112Пример:113114```c115Py_DEPRECATED(3.8) PyAPI_FUNC(int) Py_OldFunction(void);116```117118Изменено в версии 3.8: добавлена поддержка MSVC.119120**`PyDoc_STRVAR`(name, str)**121122Создаёт переменную с именем `name`, которую можно использовать в строках документации. Если Python собран без строк документации, значение будет пустым.123124Используйте [`PyDoc_STRVAR`](https://python-all.ru/3.9/c-api/intro.html#c.PyDoc_STRVAR) для строк документации, чтобы поддерживать сборку Python без строк документации, как указано в [**PEP 7**](https://python-all.ru/3.9/c-api/intro.html).125126Пример:127128```c129PyDoc_STRVAR(pop_doc, "Remove and return the rightmost element.");130131static PyMethodDef deque_methods[] = {132 // ...133 {"pop", (PyCFunction)deque_pop, METH_NOARGS, pop_doc},134 // ...135}136```137138**`PyDoc_STR`(str)**139140Создаёт строку документации для заданной входной строки или пустую строку, если строки документации отключены.141142Используйте [`PyDoc_STR`](https://python-all.ru/3.9/c-api/intro.html#c.PyDoc_STR) при указании строк документации, чтобы поддерживать сборку Python без строк документации, как указано в [**PEP 7**](https://python-all.ru/3.9/c-api/intro.html).143144Пример:145146```c147static PyMethodDef pysqlite_row_methods[] = {148 {"keys", (PyCFunction)pysqlite_row_keys, METH_NOARGS,149 PyDoc_STR("Returns the keys of the row.")},150 {NULL, NULL}151};152```153154## Объекты, типы и счетчики ссылок155156Большинство функций Python/C API принимают один или несколько аргументов и возвращают значение типа [`PyObject*`](https://python-all.ru/3.9/c-api/structures.html#c.PyObject). Этот тип является указателем на непрозрачный тип данных, представляющий произвольный объект Python. Поскольку все типы объектов Python в большинстве ситуаций обрабатываются одинаково (например, присваивание, правила видимости и передача аргументов), логично, что они должны быть представлены одним типом C. Почти все объекты Python находятся в куче: никогда не объявляется автоматическая или статическая переменная типа [`PyObject`](https://python-all.ru/3.9/c-api/structures.html#c.PyObject), можно объявить только переменные-указатели типа [`PyObject*`](https://python-all.ru/3.9/c-api/structures.html#c.PyObject). Единственное исключение – объекты типов; поскольку они никогда не должны освобождаться, они обычно являются статическими объектами [`PyTypeObject`](https://python-all.ru/3.9/c-api/type.html#c.PyTypeObject).157158Все объекты Python (даже целые числа Python) имеют *тип* и *счетчик ссылок*. Тип объекта определяет, что это за объект (например, целое число, список или пользовательская функция; существует гораздо больше типов, как описано в [Стандартная иерархия типов](https://python-all.ru/3.9/reference/datamodel.html#types)). Для каждого из известных типов существует макрос, проверяющий, является ли объект объектом этого типа; например, `PyList_Check(a)` истинно тогда и только тогда, когда объект, на который указывает *a*, является списком Python.159160### Счетчики ссылок161162Счётчик ссылок важен, потому что у современных компьютеров конечный (и зачастую сильно ограниченный) объём памяти; он показывает, сколько разных мест содержат ссылку на объект. Таким местом может быть другой объект, глобальная (или статическая) переменная C или локальная переменная в какой-нибудь функции C. Когда счётчик ссылок объекта становится нулевым, объект освобождается. Если он содержит ссылки на другие объекты, их счётчик ссылок уменьшается. Эти другие объекты могут в свою очередь быть освобождены, если это уменьшение обнулит их счётчик ссылок, и так далее. (Здесь очевидна проблема с объектами, которые ссылаются друг на друга; пока решение – «не делайте так».)163164Счётчики ссылок всегда изменяются явно. Обычно используется макрос [`Py_INCREF()`](https://python-all.ru/3.9/c-api/refcounting.html#c.Py_INCREF) для увеличения счётчика ссылок объекта на единицу и [`Py_DECREF()`](https://python-all.ru/3.9/c-api/refcounting.html#c.Py_DECREF) для уменьшения на единицу. Макрос [`Py_DECREF()`](https://python-all.ru/3.9/c-api/refcounting.html#c.Py_DECREF) значительно сложнее, чем макрос увеличения, поскольку он должен проверять, не стал ли счётчик ссылок нулевым, и затем вызывать деаллокатор объекта. Деаллокатор – это указатель на функцию, содержащийся в структуре типа объекта. Деаллокатор, специфичный для типа, занимается уменьшением счётчиков ссылок других объектов, содержащихся в данном объекте (если это составной тип, например список), а также выполняет любую дополнительную финализацию, если необходимо. Счётчик ссылок не может переполниться; для его хранения используется как минимум столько же битов, сколько уникальных адресов памяти в виртуальной памяти (при условии `sizeof(Py_ssize_t) >= sizeof(void*)`). Таким образом, увеличение счётчика ссылок – простая операция.165166Нет необходимости увеличивать счётчик ссылок объекта для каждой локальной переменной, содержащей указатель на объект. Теоретически, счётчик ссылок объекта увеличивается на единицу, когда переменная начинает на него указывать, и уменьшается на единицу, когда переменная выходит из области видимости. Однако эти изменения компенсируют друг друга, поэтому в итоге счётчик ссылок не меняется. Единственная реальная причина использовать счётчик ссылок – предотвратить освобождение объекта, пока наша переменная указывает на него. Если мы знаем, что существует хотя бы одна другая ссылка на объект, которая живёт как минимум столько же, сколько наша переменная, то нет необходимости временно увеличивать счётчик ссылок. Важная ситуация, где это возникает, – объекты, передаваемые в качестве аргументов функциям C в модуле расширения, вызываемом из Python; механизм вызова гарантирует удержание ссылки на каждый аргумент в течение всего вызова.167168Однако распространённая ошибка – извлечь объект из списка и удерживать его некоторое время, не увеличивая его счётчик ссылок. Какая-нибудь другая операция может удалить объект из списка, уменьшив его счётчик ссылок и, возможно, освободив его. Реальная опасность в том, что безобидные с виду операции могут вызвать произвольный код Python, который способен это сделать; существует путь выполнения, позволяющий вернуть управление пользователю из [`Py_DECREF()`](https://python-all.ru/3.9/c-api/refcounting.html#c.Py_DECREF), поэтому практически любая операция потенциально опасна.169170Безопасный подход – всегда использовать общие операции (функции, имена которых начинаются с `PyObject_`, `PyNumber_`, `PySequence_` или `PyMapping_`). Эти операции всегда увеличивают счётчик ссылок возвращаемого объекта. Это оставляет вызывающей стороне обязанность вызвать [`Py_DECREF()`](https://python-all.ru/3.9/c-api/refcounting.html#c.Py_DECREF), когда результат больше не нужен; это быстро входит в привычку.171172#### Подробности о счетчиках ссылок173174Поведение счётчика ссылок у функций Python/C API лучше всего объяснять в терминах *владения ссылками*. Владение относится к ссылкам, а не к объектам (объектами не владеют: они всегда разделяются). «Владеть ссылкой» означает нести ответственность за вызов Py\_DECREF для неё, когда ссылка больше не нужна. Владение также может передаваться, то есть код, получивший владение ссылкой, становится ответственным за последующий вызов [`Py_DECREF()`](https://python-all.ru/3.9/c-api/refcounting.html#c.Py_DECREF) или [`Py_XDECREF()`](https://python-all.ru/3.9/c-api/refcounting.html#c.Py_XDECREF), когда она больше не нужна, или за передачу этой ответственности дальше (обычно своему вызывающему). Когда функция передаёт владение ссылкой своему вызывающему, говорят, что вызывающий получает *новую* ссылку. Если владение не передаётся, говорят, что вызывающий *заимствует* ссылку. С заимствованной ссылкой ничего делать не нужно.175176И наоборот, когда вызывающая функция передаёт ссылку на объект, есть две возможности: функция *крадёт* ссылку на объект, или нет. *Кража ссылки* означает, что при передаче ссылки функции эта функция считает, что теперь она владеет этой ссылкой, и вы больше не несёте за неё ответственность.177178Немногие функции крадут ссылки; двумя заметными исключениями являются [`PyList_SetItem()`](https://python-all.ru/3.9/c-api/list.html#c.PyList_SetItem) и [`PyTuple_SetItem()`](https://python-all.ru/3.9/c-api/tuple.html#c.PyTuple_SetItem), которые крадут ссылку на элемент (но не на кортеж или список, в который помещается элемент!). Эти функции были спроектированы так, чтобы красть ссылку из-за распространенного идиоматического приема заполнения кортежа или списка только что созданными объектами; например, код для создания кортежа `(1, 2, "three")` может выглядеть так (пока забывая об обработке ошибок; лучший способ написать это показан ниже):179180```c181PyObject *t;182183t = PyTuple_New(3);184PyTuple_SetItem(t, 0, PyLong_FromLong(1L));185PyTuple_SetItem(t, 1, PyLong_FromLong(2L));186PyTuple_SetItem(t, 2, PyUnicode_FromString("three"));187```188189Здесь [`PyLong_FromLong()`](https://python-all.ru/3.9/c-api/long.html#c.PyLong_FromLong) возвращает новую ссылку, которая немедленно крадется [`PyTuple_SetItem()`](https://python-all.ru/3.9/c-api/tuple.html#c.PyTuple_SetItem). Если требуется продолжать использовать объект, хотя ссылка на него будет украдена, используйте [`Py_INCREF()`](https://python-all.ru/3.9/c-api/refcounting.html#c.Py_INCREF), чтобы получить другую ссылку перед вызовом функции, крадущей ссылки.190191Кстати, [`PyTuple_SetItem()`](https://python-all.ru/3.9/c-api/tuple.html#c.PyTuple_SetItem) – это *единственный* способ задать элементы кортежа. [`PySequence_SetItem()`](https://python-all.ru/3.9/c-api/sequence.html#c.PySequence_SetItem) и [`PyObject_SetItem()`](https://python-all.ru/3.9/c-api/object.html#c.PyObject_SetItem) отказываются это делать, поскольку кортежи – неизменяемый тип данных. Используйте [`PyTuple_SetItem()`](https://python-all.ru/3.9/c-api/tuple.html#c.PyTuple_SetItem) только для кортежей, которые создаёте самостоятельно.192193Эквивалентный код для заполнения списка можно написать с помощью [`PyList_New()`](https://python-all.ru/3.9/c-api/list.html#c.PyList_New) и [`PyList_SetItem()`](https://python-all.ru/3.9/c-api/list.html#c.PyList_SetItem).194195Однако на практике эти способы создания и заполнения кортежа или списка используются редко. Существует универсальная функция [`Py_BuildValue()`](https://python-all.ru/3.9/c-api/arg.html#c.Py_BuildValue), которая может создавать большинство распространённых объектов из значений C, управляемая *строкой формата*. Например, два приведённых выше блока кода можно заменить следующим (который также выполняет проверку ошибок):196197```c198PyObject *tuple, *list;199200tuple = Py_BuildValue("(iis)", 1, 2, "three");201list = Py_BuildValue("[iis]", 1, 2, "three");202```203204Гораздо чаще используются [`PyObject_SetItem()`](https://python-all.ru/3.9/c-api/object.html#c.PyObject_SetItem) и подобные функции с элементами, ссылки на которые вы только заимствуете, например, с аргументами, переданными в вашу функцию. В этом случае их поведение в отношении счётчика ссылок гораздо разумнее, так как вам не нужно увеличивать счётчик ссылок, чтобы передать ссылку («дать её украсть»). Например, эта функция устанавливает все элементы списка (на самом деле любой изменяемой последовательности) в заданный элемент:205206```c207int208set_all(PyObject *target, PyObject *item)209{210 Py_ssize_t i, n;211212 n = PyObject_Length(target);213 if (n < 0)214 return -1;215 for (i = 0; i < n; i++) {216 PyObject *index = PyLong_FromSsize_t(i);217 if (!index)218 return -1;219 if (PyObject_SetItem(target, index, item) < 0) {220 Py_DECREF(index);221 return -1;222 }223 Py_DECREF(index);224 }225 return 0;226}227```228229Ситуация немного отличается для возвращаемых значений функций. Хотя передача ссылки большинству функций не меняет обязанности по владению этой ссылкой, многие функции, возвращающие ссылку на объект, передают владение ссылкой вызывающему. Причина проста: во многих случаях возвращаемый объект создаётся на лету, и полученная ссылка является единственной ссылкой на объект. Поэтому универсальные функции, возвращающие ссылки на объекты, такие как [`PyObject_GetItem()`](https://python-all.ru/3.9/c-api/object.html#c.PyObject_GetItem) и [`PySequence_GetItem()`](https://python-all.ru/3.9/c-api/sequence.html#c.PySequence_GetItem), всегда возвращают новую ссылку (вызывающий становится владельцем ссылки).230231Важно понимать, что владение ссылкой, возвращённой функцией, зависит только от того, какая функция вызывается – *оперение* (тип объекта, переданного в качестве аргумента функции) *не играет роли!* Таким образом, при извлечении элемента из списка с помощью [`PyList_GetItem()`](https://python-all.ru/3.9/c-api/list.html#c.PyList_GetItem) ссылка не переходит во владение – но при получении того же элемента из того же списка с помощью [`PySequence_GetItem()`](https://python-all.ru/3.9/c-api/sequence.html#c.PySequence_GetItem) (которая принимает точно такие же аргументы) возвращённая ссылка переходит во владение.232233Вот пример того, как можно написать функцию, вычисляющую сумму элементов списка целых чисел; один раз с помощью [`PyList_GetItem()`](https://python-all.ru/3.9/c-api/list.html#c.PyList_GetItem), и один раз с помощью [`PySequence_GetItem()`](https://python-all.ru/3.9/c-api/sequence.html#c.PySequence_GetItem).234235```c236long237sum_list(PyObject *list)238{239 Py_ssize_t i, n;240 long total = 0, value;241 PyObject *item;242243 n = PyList_Size(list);244 if (n < 0)245 return -1; /* Не список */246 for (i = 0; i < n; i++) {247 item = PyList_GetItem(list, i); /* Не может завершиться ошибкой */248 if (!PyLong_Check(item)) continue; /* Пропустить нецелые значения */249 value = PyLong_AsLong(item);250 if (value == -1 && PyErr_Occurred())251 /* Целое число слишком велико для C long, выход */252 return -1;253 total += value;254 }255 return total;256}257```258259```c260long261sum_sequence(PyObject *sequence)262{263 Py_ssize_t i, n;264 long total = 0, value;265 PyObject *item;266 n = PySequence_Length(sequence);267 if (n < 0)268 return -1; /* Не имеет длины */269 for (i = 0; i < n; i++) {270 item = PySequence_GetItem(sequence, i);271 if (item == NULL)272 return -1; /* Не последовательность или другая ошибка */273 if (PyLong_Check(item)) {274 value = PyLong_AsLong(item);275 Py_DECREF(item);276 if (value == -1 && PyErr_Occurred())277 /* Целое число слишком велико для C long, выход */278 return -1;279 total += value;280 }281 else {282 Py_DECREF(item); /* Отказ от владения ссылкой */283 }284 }285 return total;286}287```288289### Типы290291Есть ещё несколько типов данных, которые играют важную роль в Python/C API; большинство из них – простые типы C, такие как `int`, `long`, `double` и `char*`. Несколько структурных типов используются для описания статических таблиц, в которых перечисляются функции, экспортируемые модулем, или атрибуты данных нового типа объекта, а ещё один тип используется для описания значения комплексного числа. Они будут рассмотрены вместе с функциями, которые их используют.292293**`Py_ssize_t`**294295Знаковый целочисленный тип, такой что `sizeof(Py_ssize_t) == sizeof(size_t)`. C99 не определяет такой тип напрямую (size\_t – это беззнаковый целочисленный тип). Подробнее см. [**PEP 353**](https://python-all.ru/3.9/c-api/intro.html). `PY_SSIZE_T_MAX` – это наибольшее положительное значение типа [`Py_ssize_t`](https://python-all.ru/3.9/c-api/intro.html#c.Py_ssize_t).296297## Исключения298299Программисту на Python требуется обрабатывать исключения только в тех случаях, когда необходима специфическая обработка ошибок; необработанные исключения автоматически передаются вызывающему, затем вызывающему вызывающего и так далее, пока не достигнут интерпретатора верхнего уровня, где они сообщаются пользователю вместе с трассировкой стека.300301Однако для C-программистов проверка ошибок всегда должна быть явной. Все функции Python/C API могут вызывать исключения, если в документации функции не указано иное. В общем случае, когда функция обнаруживает ошибку, она устанавливает исключение, отбрасывает все принадлежащие ей ссылки на объекты и возвращает индикатор ошибки. Если не задокументировано иное, этот индикатор – либо `NULL`, либо `-1`, в зависимости от типа возвращаемого значения функции. Некоторые функции возвращают логический результат true/false, где false указывает на ошибку. Очень немногие функции не возвращают явного индикатора ошибки или имеют неоднозначное возвращаемое значение и требуют явной проверки на ошибки с помощью [`PyErr_Occurred()`](https://python-all.ru/3.9/c-api/exceptions.html#c.PyErr_Occurred). Такие исключения всегда явно документируются.302303Состояние исключения хранится в памяти, привязанной к потоку (это эквивалентно использованию глобальной памяти в однопоточном приложении). Поток может находиться в одном из двух состояний: произошло исключение или нет. Функция [`PyErr_Occurred()`](https://python-all.ru/3.9/c-api/exceptions.html#c.PyErr_Occurred) может использоваться для проверки этого: она возвращает заимствованную ссылку на объект типа исключения, если произошло исключение, и `NULL` в противном случае. Существует ряд функций для установки состояния исключения: [`PyErr_SetString()`](https://python-all.ru/3.9/c-api/exceptions.html#c.PyErr_SetString) является наиболее распространённой (хотя и не самой общей) функцией для установки состояния исключения, а [`PyErr_Clear()`](https://python-all.ru/3.9/c-api/exceptions.html#c.PyErr_Clear) очищает состояние исключения.304305Полное состояние исключения состоит из трёх объектов (все они могут быть `NULL`): типа исключения, соответствующего значения исключения и трассировки стека. Они имеют тот же смысл, что и результат Python `sys.exc_info()`; однако они не одно и то же: объекты Python представляют последнее исключение, обрабатываемое оператором [`try`](https://python-all.ru/3.9/reference/compound_stmts.html#try) … [`except`](https://python-all.ru/3.9/reference/compound_stmts.html#except), в то время как состояние исключения на уровне C существует только пока исключение передаётся между C-функциями, пока не достигнет основного цикла интерпретатора байт-кода Python, который заботится о его передаче в `sys.exc_info()` и подобные.306307Обратите внимание, что начиная с Python 1.5 предпочтительным потокобезопасным способом доступа к состоянию исключения из кода Python является вызов функции [`sys.exc_info()`](https://python-all.ru/3.9/library/sys.html#sys.exc_info), которая возвращает состояние исключения для текущего потока в коде Python. Кроме того, семантика обоих способов доступа к состоянию исключения была изменена таким образом, что функция, перехватывающая исключение, сохраняет и восстанавливает состояние исключения своего потока, чтобы сохранить состояние исключения вызывающей функции. Это предотвращает распространённые ошибки в коде обработки исключений, вызванные тем, что безобидная на вид функция перезаписывает обрабатываемое исключение; это также уменьшает часто нежелательное продление времени жизни объектов, на которые ссылаются кадры стека в трассировке.308309В качестве общего принципа: функция, которая вызывает другую функцию для выполнения некоторой задачи, должна проверять, вызвала ли вызываемая функция исключение, и если да, передавать состояние исключения своему вызывающему. Она должна отбрасывать все принадлежащие ей ссылки на объекты и возвращать индикатор ошибки, но *не* должна устанавливать другое исключение – это перезапишет только что вызванное исключение и приведёт к потере важной информации о точной причине ошибки.310311Простой пример обнаружения исключений и их передачи показан в примере `sum_sequence()` выше. Так получилось, что этому примеру не нужно очищать принадлежащие ссылки при обнаружении ошибки. Следующая примерная функция показывает некоторую очистку при ошибке. Сначала, чтобы напомнить о преимуществах Python, приведён эквивалентный код на Python:312313```c314def incr_item(dict, key):315 try:316 item = dict[key]317 except KeyError:318 item = 0319 dict[key] = item + 1320```321322А вот соответствующий код на C во всей своей красе:323324```c325int326incr_item(PyObject *dict, PyObject *key)327{328 /* Все объекты инициализированы в NULL для Py_XDECREF */329 PyObject *item = NULL, *const_one = NULL, *incremented_item = NULL;330 int rv = -1; /* Возвращаемое значение инициализировано как -1 (ошибка) */331332 item = PyObject_GetItem(dict, key);333 if (item == NULL) {334 /* Обрабатывать только KeyError: */335 if (!PyErr_ExceptionMatches(PyExc_KeyError))336 goto error;337338 /* Очистить ошибку и использовать ноль: */339 PyErr_Clear();340 item = PyLong_FromLong(0L);341 if (item == NULL)342 goto error;343 }344 const_one = PyLong_FromLong(1L);345 if (const_one == NULL)346 goto error;347348 incremented_item = PyNumber_Add(item, const_one);349 if (incremented_item == NULL)350 goto error;351352 if (PyObject_SetItem(dict, key, incremented_item) < 0)353 goto error;354 rv = 0; /* Успех */355 /* Продолжить с кодом очистки */356357 error:358 /* Код очистки, общий для путей успеха и ошибки */359360 /* Используйте Py_XDECREF() для игнорирования NULL-ссылок */361 Py_XDECREF(item);362 Py_XDECREF(const_one);363 Py_XDECREF(incremented_item);364365 return rv; /* -1 для ошибки, 0 для успеха */366}367```368369Этот пример демонстрирует одобренное использование оператора `goto` в C! Он иллюстрирует применение [`PyErr_ExceptionMatches()`](https://python-all.ru/3.9/c-api/exceptions.html#c.PyErr_ExceptionMatches) и [`PyErr_Clear()`](https://python-all.ru/3.9/c-api/exceptions.html#c.PyErr_Clear) для обработки конкретных исключений, а также использование [`Py_XDECREF()`](https://python-all.ru/3.9/c-api/refcounting.html#c.Py_XDECREF) для освобождения собственных ссылок, которые могут быть `NULL` (обратите внимание на `'X'` в имени; [`Py_DECREF()`](https://python-all.ru/3.9/c-api/refcounting.html#c.Py_DECREF) приведёт к аварийному завершению при встрече с ссылкой `NULL`). Важно, чтобы переменные, используемые для хранения собственных ссылок, были инициализированы `NULL` для корректной работы; аналогично, предполагаемое возвращаемое значение инициализируется `-1` (означает неудачу) и устанавливается в успех только после успешного выполнения последнего вызова.370371## Встраивание Python372373Единственная важная задача, о которой должны беспокоиться только разработчики, встраивающие интерпретатор Python (в отличие от разработчиков расширений), – это инициализация и, возможно, финализация интерпретатора Python. Большинство функций интерпретатора могут использоваться только после его инициализации.374375Основная функция инициализации – [`Py_Initialize()`](https://python-all.ru/3.9/c-api/init.html#c.Py_Initialize). Она инициализирует таблицу загруженных модулей и создаёт фундаментальные модули [`builtins`](https://python-all.ru/3.9/library/builtins.html#module-builtins), [`__main__`](https://python-all.ru/3.9/library/__main__.html#module-__main__) и [`sys`](https://python-all.ru/3.9/library/sys.html#module-sys). Также она инициализирует путь поиска модулей (`sys.path`).376377[`Py_Initialize()`](https://python-all.ru/3.9/c-api/init.html#c.Py_Initialize) не устанавливает «список аргументов скрипта» (`sys.argv`). Если эта переменная понадобится коду Python, который будет выполняться позже, её необходимо явно установить с помощью вызова `PySys_SetArgvEx(argc, argv, updatepath)` после вызова [`Py_Initialize()`](https://python-all.ru/3.9/c-api/init.html#c.Py_Initialize).378379В большинстве систем (в частности, в Unix и Windows, хотя детали несколько различаются) [`Py_Initialize()`](https://python-all.ru/3.9/c-api/init.html#c.Py_Initialize) вычисляет путь поиска модулей, основываясь на наилучшем предположении о местоположении исполняемого файла стандартного интерпретатора Python, предполагая, что библиотека Python находится в фиксированном месте относительно исполняемого файла интерпретатора Python. В частности, он ищет каталог с именем `lib/pythonX.Y` относительно родительского каталога, где находится исполняемый файл с именем `python` в пути поиска команд оболочки (переменная окружения `PATH`).380381Например, если исполняемый файл Python находится в `/usr/local/bin/python`, то будет предполагаться, что библиотеки находятся в `/usr/local/lib/pythonX.Y`. (Фактически, этот конкретный путь также является «запасным» местоположением, используемым, когда исполняемый файл с именем `python` не найден вдоль `PATH`.) Пользователь может переопределить это поведение, установив переменную окружения [`PYTHONHOME`](https://python-all.ru/3.9/using/cmdline.html#envvar-PYTHONHOME), или вставить дополнительные каталоги в начало стандартного пути, установив [`PYTHONPATH`](https://python-all.ru/3.9/using/cmdline.html#envvar-PYTHONPATH).382383Встраивающее приложение может управлять поиском, вызвав `Py_SetProgramName(file)` *перед* вызовом [`Py_Initialize()`](https://python-all.ru/3.9/c-api/init.html#c.Py_Initialize). Обратите внимание, что [`PYTHONHOME`](https://python-all.ru/3.9/using/cmdline.html#envvar-PYTHONHOME) по-прежнему переопределяет это, а [`PYTHONPATH`](https://python-all.ru/3.9/using/cmdline.html#envvar-PYTHONPATH) всё ещё вставляется перед стандартным путём. Приложение, требующее полного контроля, должно предоставить собственную реализацию [`Py_GetPath()`](https://python-all.ru/3.9/c-api/init.html#c.Py_GetPath), [`Py_GetPrefix()`](https://python-all.ru/3.9/c-api/init.html#c.Py_GetPrefix), [`Py_GetExecPrefix()`](https://python-all.ru/3.9/c-api/init.html#c.Py_GetExecPrefix) и [`Py_GetProgramFullPath()`](https://python-all.ru/3.9/c-api/init.html#c.Py_GetProgramFullPath) (все они определены в `Modules/getpath.c`).384385Иногда бывает желательно «деинициализировать» Python. Например, приложение может захотеть начать заново (сделать ещё один вызов [`Py_Initialize()`](https://python-all.ru/3.9/c-api/init.html#c.Py_Initialize)) или просто завершить использование Python и освободить память, выделенную Python. Это можно сделать, вызвав [`Py_FinalizeEx()`](https://python-all.ru/3.9/c-api/init.html#c.Py_FinalizeEx). Функция [`Py_IsInitialized()`](https://python-all.ru/3.9/c-api/init.html#c.Py_IsInitialized) возвращает true, если Python в настоящее время находится в инициализированном состоянии. Дополнительная информация об этих функциях приведена в следующей главе. Обратите внимание, что [`Py_FinalizeEx()`](https://python-all.ru/3.9/c-api/init.html#c.Py_FinalizeEx) *не* освобождает всю память, выделенную интерпретатором Python, например, память, выделенная модулями расширения, в настоящее время не может быть освобождена.386387## Отладочные сборки388389Python может быть собран с несколькими макросами для включения дополнительных проверок интерпретатора и модулей расширения. Эти проверки, как правило, добавляют значительные накладные расходы во время выполнения, поэтому они не включены по умолчанию.390391Полный список различных типов отладочных сборок находится в файле `Misc/SpecialBuilds.txt` в дистрибутиве исходного кода Python. Доступны сборки, которые поддерживают трассировку счётчиков ссылок, отладку распределителя памяти или низкоуровневое профилирование основного цикла интерпретатора. В оставшейся части раздела будут описаны только наиболее часто используемые сборки.392393Компиляция интерпретатора с определённым макросом `Py_DEBUG` даёт то, что обычно называют «отладочной сборкой» Python. `Py_DEBUG` включается в сборке Unix добавлением `--with-pydebug` к команде `./configure`. Он также подразумевается наличием не связанного с Python макроса `_DEBUG`. Когда `Py_DEBUG` включён в сборке Unix, оптимизация компилятора отключается.394395В дополнение к отладке счётчика ссылок, описанной ниже, выполняются следующие дополнительные проверки:396397- Дополнительные проверки добавлены в распределитель объектов.398- Дополнительные проверки добавлены в синтаксический анализатор и компилятор.399- Проверяются понижающие приведения от широких типов к узким на предмет потери информации.400- В реализации словаря и множества добавлен ряд утверждений. Кроме того, объект множества получает метод `test_c_api()`.401- Проверки корректности входных аргументов добавлены при создании фрейма.402- Память для целых чисел инициализируется известным недопустимым шаблоном для выявления ссылок на неинициализированные разряды.403- Низкоуровневая трассировка и дополнительные проверки исключений добавлены в виртуальную машину времени выполнения.404- Дополнительные проверки добавлены в реализацию области памяти (arena).405- Дополнительная отладка добавлена в модуль thread.406407Могут быть и другие проверки, не упомянутые здесь.408409Определение `Py_TRACE_REFS` включает трассировку ссылок. При определении поддерживается циклический двусвязный список активных объектов за счёт добавления двух дополнительных полей к каждому [`PyObject`](https://python-all.ru/3.9/c-api/structures.html#c.PyObject). Также отслеживается общее количество выделений. При выходе печатаются все существующие ссылки. (В интерактивном режиме это происходит после каждого оператора, выполненного интерпретатором.) Подразумевается определением `Py_DEBUG`.410411См. `Misc/SpecialBuilds.txt` в дистрибутиве исходных текстов Python для получения более подробной информации.412