intro.md
1> **Источник:** https://python-all.ru/3.0/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Написание модуля расширения – процесс относительно хорошо понятный, и здесь хорошо работает подход «сборника рецептов». Существует несколько инструментов, которые автоматизируют процесс в той или иной степени. Хотя Python встраивали в другие приложения с самого его появления, процесс встраивания Python менее прямолинеен, чем написание расширения.1213Многие функции API полезны независимо от того, встраивается Python или расширяется; более того, большинство приложений, встраивающих Python, также должны предоставлять собственное расширение, поэтому, вероятно, стоит ознакомиться с написанием расширения, прежде чем пытаться встроить Python в реальное приложение.1415## Заголовочные файлы1617Все определения функций, типов и макросов, необходимые для использования Python/C API, включаются в код с помощью следующей строки:1819```c20#include "Python.h"21```2223Это подразумевает включение следующих стандартных заголовков: `<stdio.h>`, `<string.h>`, `<errno.h>`, `<limits.h>` и `<stdlib.h>` (если доступны).2425> **Предупреждение**26>27> Поскольку Python может определять некоторые макросы препроцессора, влияющие на стандартные заголовки в некоторых системах, необходимо *обязательно* включать `Python.h` до включения любых стандартных заголовков.2829Все видимые пользователю имена, определённые в Python.h (кроме тех, что определены включёнными стандартными заголовками), имеют один из префиксов `Py` или `_Py`. Имена, начинающиеся с `_Py`, предназначены для внутреннего использования реализацией Python и не должны использоваться разработчиками расширений. Имена членов структур не имеют зарезервированного префикса.3031**Важно:** пользовательский код никогда не должен определять имена, начинающиеся с `Py` или `_Py`. Это сбивает с толку читателя и ставит под угрозу переносимость пользовательского кода на будущие версии Python, которые могут определять дополнительные имена, начинающиеся с одного из этих префиксов.3233Заголовочные файлы обычно устанавливаются вместе с Python. В Unix они находятся в каталогах `prefix/include/pythonversion/` и `exec_prefix/include/pythonversion/`, где **prefix** и **exec\_prefix** определяются соответствующими параметрами скрипта **configure** из Python, а *версия* равна `sys.version[:3]`. В Windows заголовочные файлы устанавливаются в `prefix/include`, где **prefix** – это каталог установки, указанный программе установки.3435Чтобы включить заголовочные файлы, поместите оба каталога (если они различаются) в путь поиска заголовочных файлов компилятора. *Не* помещайте родительские каталоги в путь поиска, а затем используйте `#include <pythonX.Y/Python.h>`; это нарушит сборку на нескольких платформах, поскольку платформонезависимые заголовочные файлы из **prefix** включают платформозависимые заголовочные файлы из **exec\_prefix**.3637Пользователям C++ следует помнить, что хотя API полностью определён на C, заголовочные файлы корректно объявляют точки входа как `extern "C"`, поэтому нет необходимости делать что-то особенное для использования API из C++.3839## Объекты, типы и счетчики ссылок4041Большинство функций Python/C API имеют один или несколько аргументов, а также возвращаемое значение типа [`PyObject*`](https://python-all.ru/3.0/c-api/structures.html#PyObject). Этот тип является указателем на непрозрачный тип данных, представляющий произвольный объект Python. Поскольку все типы объектов Python обрабатываются одинаково в большинстве ситуаций (например, присваивания, правила области видимости и передача аргументов), вполне естественно, что они представляются одним C-типом. Почти все объекты Python находятся в куче: никогда не объявляются автоматические или статические переменные типа [`PyObject`](https://python-all.ru/3.0/c-api/structures.html#PyObject), можно объявлять только переменные-указатели типа [`PyObject*`](https://python-all.ru/3.0/c-api/structures.html#PyObject). Единственное исключение – объекты типов; поскольку они никогда не должны освобождаться, они обычно являются статическими объектами [`PyTypeObject`](https://python-all.ru/3.0/c-api/type.html#PyTypeObject).4243All Python objects (even Python integers) have a *type* and a *reference count*. An object’s type determines what kind of object it is (e.g., an integer, a list, or a user-defined function; there are many more as explained in [*The standard type hierarchy*](https://python-all.ru/3.0/reference/datamodel.html#types)). For each of the well-known types there is a macro to check whether an object is of that type; for instance, `PyList_Check(a)` is true if (and only if) the object pointed to by *a* is a Python list.4445### Счетчики ссылок4647Счётчик ссылок важен, потому что у современных компьютеров конечный (и зачастую сильно ограниченный) объём памяти; он показывает, сколько разных мест содержат ссылку на объект. Таким местом может быть другой объект, глобальная (или статическая) переменная C или локальная переменная в какой-нибудь функции C. Когда счётчик ссылок объекта становится нулевым, объект освобождается. Если он содержит ссылки на другие объекты, их счётчик ссылок уменьшается. Эти другие объекты могут в свою очередь быть освобождены, если это уменьшение обнулит их счётчик ссылок, и так далее. (Здесь очевидна проблема с объектами, которые ссылаются друг на друга; пока решение – «не делайте так».)4849Счётчики ссылок всегда управляются явно. Обычный способ – использовать макрос [`Py_INCREF`](https://python-all.ru/3.0/c-api/refcounting.html#Py_INCREF) для увеличения счётчика ссылок объекта на единицу, и [`Py_DECREF`](https://python-all.ru/3.0/c-api/refcounting.html#Py_DECREF) для уменьшения на единицу. Макрос [`Py_DECREF`](https://python-all.ru/3.0/c-api/refcounting.html#Py_DECREF) значительно сложнее, чем макрос увеличения, поскольку он должен проверять, не стал ли счётчик ссылок равным нулю, и затем вызывать деаллокатор объекта. Деаллокатор – это указатель на функцию, содержащийся в структуре типа объекта. Деаллокатор, специфичный для типа, заботится об уменьшении счётчиков ссылок для других объектов, содержащихся в данном объекте, если это составной тип, такой как список, а также выполняет любую дополнительную финализацию, которая необходима. Нет возможности переполнения счётчика ссылок; для его хранения используется как минимум столько же бит, сколько различных адресов памяти в виртуальной памяти (при условии `sizeof(Py_ssize_t) >= sizeof(void*)`). Таким образом, увеличение счётчика ссылок – простая операция.5051Нет необходимости увеличивать счётчик ссылок объекта для каждой локальной переменной, содержащей указатель на объект. Теоретически, счётчик ссылок объекта увеличивается на единицу, когда переменная начинает на него указывать, и уменьшается на единицу, когда переменная выходит из области видимости. Однако эти изменения компенсируют друг друга, поэтому в итоге счётчик ссылок не меняется. Единственная реальная причина использовать счётчик ссылок – предотвратить освобождение объекта, пока наша переменная указывает на него. Если мы знаем, что существует хотя бы одна другая ссылка на объект, которая живёт как минимум столько же, сколько наша переменная, то нет необходимости временно увеличивать счётчик ссылок. Важная ситуация, где это возникает, – объекты, передаваемые в качестве аргументов функциям C в модуле расширения, вызываемом из Python; механизм вызова гарантирует удержание ссылки на каждый аргумент в течение всего вызова.5253Однако распространённая ошибка – извлечь объект из списка и удерживать его некоторое время, не увеличивая его счётчик ссылок. Другая операция может теоретически удалить объект из списка, уменьшив его счётчик ссылок и, возможно, освободив его. Реальная опасность в том, что безобидные на вид операции могут вызвать произвольный код Python, способный на это; существует путь выполнения, который позволяет управлению вернуться к пользователю из [`Py_DECREF`](https://python-all.ru/3.0/c-api/refcounting.html#Py_DECREF), поэтому практически любая операция потенциально опасна.5455Безопасный подход – всегда использовать общие операции (функции, имена которых начинаются с `PyObject_`, `PyNumber_`, `PySequence_` или `PyMapping_`). Эти операции всегда увеличивают счётчик ссылок возвращаемого объекта. Это оставляет вызывающей стороне ответственность за вызов [`Py_DECREF`](https://python-all.ru/3.0/c-api/refcounting.html#Py_DECREF) после завершения работы с результатом; это быстро становится привычным.5657#### Подробности о счетчиках ссылок5859Поведение счётчиков ссылок функций в Python/C API лучше всего объяснять в терминах *владения ссылками*. Владение относится к ссылкам, а не к объектам (объекты не принадлежат никому: они всегда разделяются). «Владеть ссылкой» означает отвечать за вызов Py\_DECREF для неё, когда ссылка больше не нужна. Владение также может передаваться; это означает, что код, получающий владение ссылкой, становится ответственным за её последующее уменьшение вызовом [`Py_DECREF`](https://python-all.ru/3.0/c-api/refcounting.html#Py_DECREF) или [`Py_XDECREF`](https://python-all.ru/3.0/c-api/refcounting.html#Py_XDECREF), когда она больше не нужна, или за передачу этой ответственности (обычно своему вызывающему). Когда функция передаёт владение ссылкой вызывающей стороне, говорят, что вызывающая сторона получает *новую* ссылку. Если владение не передаётся, говорят, что вызывающая сторона *заимствует* ссылку. С заимствованной ссылкой ничего делать не нужно.6061И наоборот, когда вызывающая функция передаёт функции ссылку на объект, есть две возможности: функция *крадёт* ссылку на объект или нет. *Кража ссылки* означает, что когда вы передаёте ссылку функции, эта функция предполагает, что теперь она владеет этой ссылкой, и вы больше не несёте за неё ответственность.6263Немногие функции крадут ссылки; два заметных исключения – [`PyList_SetItem`](https://python-all.ru/3.0/c-api/list.html#PyList_SetItem) и [`PyTuple_SetItem`](https://python-all.ru/3.0/c-api/tuple.html#PyTuple_SetItem), которые крадут ссылку на элемент (но не на кортеж или список, в который помещается элемент!). Эти функции были спроектированы для кражи ссылки из-за распространённой идиомы заполнения кортежа или списка только что созданными объектами; например, код для создания кортежа `(1, 2, "three")` мог бы выглядеть так (пока забыв об обработке ошибок; более правильный способ показан ниже):6465```c66PyObject *t;6768t = PyTuple_New(3);69PyTuple_SetItem(t, 0, PyLong_FromLong(1L));70PyTuple_SetItem(t, 1, PyLong_FromLong(2L));71PyTuple_SetItem(t, 2, PyString_FromString("three"));72```7374Здесь [`PyLong_FromLong`](https://python-all.ru/3.0/c-api/long.html#PyLong_FromLong) возвращает новую ссылку, которая немедленно крадётся [`PyTuple_SetItem`](https://python-all.ru/3.0/c-api/tuple.html#PyTuple_SetItem). Если вы хотите продолжать использовать объект, хотя ссылка на него будет украдена, используйте [`Py_INCREF`](https://python-all.ru/3.0/c-api/refcounting.html#Py_INCREF), чтобы получить другую ссылку перед вызовом функции, крадущей ссылки.7576Кстати, [`PyTuple_SetItem`](https://python-all.ru/3.0/c-api/tuple.html#PyTuple_SetItem) – это *единственный* способ установить элементы кортежа; [`PySequence_SetItem`](https://python-all.ru/3.0/c-api/sequence.html#PySequence_SetItem) и [`PyObject_SetItem`](https://python-all.ru/3.0/c-api/object.html#PyObject_SetItem) отказываются это делать, поскольку кортежи являются неизменяемым типом данных. Следует использовать [`PyTuple_SetItem`](https://python-all.ru/3.0/c-api/tuple.html#PyTuple_SetItem) только для кортежей, которые вы создаёте самостоятельно.7778Эквивалентный код для заполнения списка можно написать с помощью [`PyList_New`](https://python-all.ru/3.0/c-api/list.html#PyList_New) и [`PyList_SetItem`](https://python-all.ru/3.0/c-api/list.html#PyList_SetItem).7980Однако на практике вы редко будете использовать эти способы создания и заполнения кортежа или списка. Существует общая функция [`Py_BuildValue`](https://python-all.ru/3.0/c-api/arg.html#Py_BuildValue), которая может создавать большинство распространённых объектов из значений C, руководствуясь *строкой формата*. Например, два приведённых выше блока кода можно заменить следующим (которое также заботится о проверке ошибок):8182```c83PyObject *tuple, *list;8485tuple = Py_BuildValue("(iis)", 1, 2, "three");86list = Py_BuildValue("[iis]", 1, 2, "three");87```8889Гораздо чаще используется [`PyObject_SetItem`](https://python-all.ru/3.0/c-api/object.html#PyObject_SetItem) и подобные ей с элементами, ссылки на которые вы только заимствуете, например, аргументы, переданные в функцию, которую вы пишете. В этом случае их поведение в отношении счётчиков ссылок гораздо разумнее, поскольку вам не нужно увеличивать счётчик ссылок, чтобы отдать ссылку («позволить её украсть»). Например, эта функция устанавливает все элементы списка (фактически любой изменяемой последовательности) в заданный элемент:9091```c92int93set_all(PyObject *target, PyObject *item)94{95 int i, n;9697 n = PyObject_Length(target);98 if (n < 0)99 return -1;100 for (i = 0; i < n; i++) {101 PyObject *index = PyLong_FromLong(i);102 if (!index)103 return -1;104 if (PyObject_SetItem(target, index, item) < 0)105 return -1;106 Py_DECREF(index);107 }108 return 0;109}110```111112Ситуация немного отличается для возвращаемых значений функций. Хотя передача ссылки большинству функций не меняет ваших обязанностей по владению этой ссылкой, многие функции, возвращающие ссылку на объект, передают вам владение ссылкой. Причина проста: во многих случаях возвращаемый объект создаётся на лету, и полученная ссылка является единственной ссылкой на объект. Поэтому общие функции, возвращающие ссылки на объекты, такие как [`PyObject_GetItem`](https://python-all.ru/3.0/c-api/object.html#PyObject_GetItem) и [`PySequence_GetItem`](https://python-all.ru/3.0/c-api/sequence.html#PySequence_GetItem), всегда возвращают новую ссылку (вызывающий становится владельцем ссылки).113114Важно понимать, что владение ссылкой, возвращённой функцией, зависит только от того, какую функцию вы вызываете – *оперение* (тип объекта, переданного в качестве аргумента функции) *здесь ни при чём!* Таким образом, если вы извлекаете элемент из списка с помощью [`PyList_GetItem`](https://python-all.ru/3.0/c-api/list.html#PyList_GetItem), вы не владеете ссылкой – но если вы получаете тот же элемент из того же списка с помощью [`PySequence_GetItem`](https://python-all.ru/3.0/c-api/sequence.html#PySequence_GetItem) (которая принимает точно те же аргументы), вы владеете ссылкой на возвращённый объект.115116Вот пример того, как можно написать функцию, вычисляющую сумму элементов списка целых чисел; один раз с использованием [`PyList_GetItem`](https://python-all.ru/3.0/c-api/list.html#PyList_GetItem), и один раз с использованием [`PySequence_GetItem`](https://python-all.ru/3.0/c-api/sequence.html#PySequence_GetItem).117118```c119long120sum_list(PyObject *list)121{122 int i, n;123 long total = 0;124 PyObject *item;125126 n = PyList_Size(list);127 if (n < 0)128 return -1; /* Не список */129 for (i = 0; i < n; i++) {130 item = PyList_GetItem(list, i); /* Не может завершиться ошибкой */131 if (!PyLong_Check(item)) continue; /* Пропустить нецелые значения */132 total += PyLong_AsLong(item);133 }134 return total;135}136```137138```c139long140sum_sequence(PyObject *sequence)141{142 int i, n;143 long total = 0;144 PyObject *item;145 n = PySequence_Length(sequence);146 if (n < 0)147 return -1; /* Не имеет длины */148 for (i = 0; i < n; i++) {149 item = PySequence_GetItem(sequence, i);150 if (item == NULL)151 return -1; /* Не последовательность или другая ошибка */152 if (PyLong_Check(item))153 total += PyLong_AsLong(item);154 Py_DECREF(item); /* Отказ от владения ссылкой */155 }156 return total;157}158```159160### Типы161162Существует несколько других типов данных, играющих важную роль в Python/C API; большинство из них – простые C-типы, такие как `int`, `long`, `double` и `char*`. Некоторые структурные типы используются для описания статических таблиц, перечисляющих функции, экспортируемые модулем, или атрибуты данных нового типа объекта, а ещё один – для описания значения комплексного числа. Они будут рассмотрены вместе с функциями, которые их используют.163164## Исключения165166Программисту на Python требуется обрабатывать исключения только в тех случаях, когда необходима специфическая обработка ошибок; необработанные исключения автоматически передаются вызывающему, затем вызывающему вызывающего и так далее, пока не достигнут интерпретатора верхнего уровня, где они сообщаются пользователю вместе с трассировкой стека.167168Однако для программистов на C проверка ошибок всегда должна быть явной. Все функции в Python/C API могут вызывать исключения, если только в документации функции не указано иное. В общем случае, когда функция встречает ошибку, она устанавливает исключение, отбрасывает все принадлежащие ей ссылки на объекты и возвращает индикатор ошибки – обычно *NULL* или `-1`. Некоторые функции возвращают логический результат true/false, где false указывает на ошибку. Очень немногие функции не возвращают явного индикатора ошибки или имеют неоднозначное возвращаемое значение и требуют явной проверки ошибок с помощью [`PyErr_Occurred`](https://python-all.ru/3.0/c-api/exceptions.html#PyErr_Occurred).169170Состояние исключения хранится в локальном хранилище потока (это эквивалентно использованию глобального хранилища в однопоточном приложении). Поток может находиться в одном из двух состояний: исключение произошло или нет. Функция [`PyErr_Occurred`](https://python-all.ru/3.0/c-api/exceptions.html#PyErr_Occurred) может использоваться для проверки этого: она возвращает заимствованную ссылку на объект типа исключения, если исключение произошло, и *NULL* в противном случае. Существует ряд функций для установки состояния исключения: [`PyErr_SetString`](https://python-all.ru/3.0/c-api/exceptions.html#PyErr_SetString) – самая распространённая (хотя и не самая общая) функция для установки состояния исключения, а [`PyErr_Clear`](https://python-all.ru/3.0/c-api/exceptions.html#PyErr_Clear) очищает состояние исключения.171172Полное состояние исключения состоит из трёх объектов (все могут быть *NULL*): тип исключения, соответствующее значение исключения и traceback. Они имеют тот же смысл, что и результат Python `sys.exc_info()`; однако это не одно и то же: объекты Python представляют последнее исключение, обрабатываемое оператором Python [`try`](https://python-all.ru/3.0/reference/compound_stmts.html#try) ... [`except`](https://python-all.ru/3.0/reference/compound_stmts.html#except), в то время как состояние исключения на уровне C существует только пока исключение передаётся между функциями C, пока не достигнет главного цикла интерпретатора байт-кода Python, который заботится о его передаче в `sys.exc_info()` и подобные функции.173174Обратите внимание, что начиная с Python 1.5 предпочтительным поточнобезопасным способом доступа к состоянию исключения из кода Python является вызов функции [`sys.exc_info()`](https://python-all.ru/3.0/library/sys.html#sys.exc_info), которая возвращает состояние исключения для текущего потока для кода Python. Кроме того, семантика обоих способов доступа к состоянию исключения изменилась так, что функция, перехватывающая исключение, сохраняет и восстанавливает состояние исключения своего потока, чтобы сохранить состояние исключения вызывающего кода. Это предотвращает распространённые ошибки в коде обработки исключений, вызванные тем, что безобидная с виду функция перезаписывает обрабатываемое исключение; это также уменьшает часто нежелательное продление времени жизни объектов, на которые ссылаются кадры стека в traceback.175176В качестве общего принципа: функция, которая вызывает другую функцию для выполнения некоторой задачи, должна проверять, вызвала ли вызываемая функция исключение, и если да, передавать состояние исключения своему вызывающему. Она должна отбрасывать все принадлежащие ей ссылки на объекты и возвращать индикатор ошибки, но *не* должна устанавливать другое исключение – это перезапишет только что вызванное исключение и приведёт к потере важной информации о точной причине ошибки.177178Простой пример обнаружения исключений и их передачи показан в примере `sum_sequence` выше. Так получилось, что в этом примере не нужно очищать принадлежащие ссылки при обнаружении ошибки. Следующий пример функции показывает некоторую очистку при ошибках. Сначала, чтобы напомнить, почему вам нравится Python, мы показываем эквивалентный код Python:179180```c181def incr_item(dict, key):182 try:183 item = dict[key]184 except KeyError:185 item = 0186 dict[key] = item + 1187```188189А вот соответствующий код на C во всей своей красе:190191```c192int193incr_item(PyObject *dict, PyObject *key)194{195 /* Все объекты инициализированы в NULL для Py_XDECREF */196 PyObject *item = NULL, *const_one = NULL, *incremented_item = NULL;197 int rv = -1; /* Возвращаемое значение инициализировано как -1 (ошибка) */198199 item = PyObject_GetItem(dict, key);200 if (item == NULL) {201 /* Обрабатывать только KeyError: */202 if (!PyErr_ExceptionMatches(PyExc_KeyError))203 goto error;204205 /* Очистить ошибку и использовать ноль: */206 PyErr_Clear();207 item = PyLong_FromLong(0L);208 if (item == NULL)209 goto error;210 }211 const_one = PyLong_FromLong(1L);212 if (const_one == NULL)213 goto error;214215 incremented_item = PyNumber_Add(item, const_one);216 if (incremented_item == NULL)217 goto error;218219 if (PyObject_SetItem(dict, key, incremented_item) < 0)220 goto error;221 rv = 0; /* Успех */222 /* Продолжить с кодом очистки */223224 error:225 /* Код очистки, общий для путей успеха и ошибки */226227 /* Используйте Py_XDECREF() для игнорирования NULL-ссылок */228 Py_XDECREF(item);229 Py_XDECREF(const_one);230 Py_XDECREF(incremented_item);231232 return rv; /* -1 для ошибки, 0 для успеха */233}234```235236Этот пример представляет собой одобренное использование оператора `goto` в C! Он иллюстрирует использование [`PyErr_ExceptionMatches`](https://python-all.ru/3.0/c-api/exceptions.html#PyErr_ExceptionMatches) и [`PyErr_Clear`](https://python-all.ru/3.0/c-api/exceptions.html#PyErr_Clear) для обработки конкретных исключений, и использование [`Py_XDECREF`](https://python-all.ru/3.0/c-api/refcounting.html#Py_XDECREF) для освобождения принадлежащих ссылок, которые могут быть *NULL* (обратите внимание на `'X'` в имени; [`Py_DECREF`](https://python-all.ru/3.0/c-api/refcounting.html#Py_DECREF) аварийно завершился бы при столкновении с ссылкой *NULL*). Важно, чтобы переменные, используемые для хранения принадлежащих ссылок, были инициализированы как *NULL* для корректной работы; аналогично, предполагаемое возвращаемое значение инициализируется как `-1` (ошибка) и устанавливается в успех только после того, как последний вызов завершится успешно.237238## Встраивание Python239240Единственная важная задача, о которой должны беспокоиться только разработчики, встраивающие интерпретатор Python (в отличие от разработчиков расширений), – это инициализация и, возможно, финализация интерпретатора Python. Большинство функций интерпретатора могут использоваться только после его инициализации.241242Основная функция инициализации – [`Py_Initialize`](https://python-all.ru/3.0/c-api/init.html#Py_Initialize). Она инициализирует таблицу загруженных модулей и создаёт фундаментальные модули [`builtins`](https://python-all.ru/3.0/library/builtins.html#module-builtins), [`__main__`](https://python-all.ru/3.0/library/__main__.html#module-__main__), [`sys`](https://python-all.ru/3.0/library/sys.html#module-sys) и [`exceptions`](https://python-all.ru/3.0/library/exceptions.html#module-exceptions). А также инициализирует путь поиска модулей (`sys.path`).243244[`Py_Initialize`](https://python-all.ru/3.0/c-api/init.html#Py_Initialize) не устанавливает «список аргументов сценария» (`sys.argv`). Если эта переменная необходима Python-коду, который будет выполняться позже, она должна быть явно установлена вызовом `PySys_SetArgv(argc, argv)` после вызова [`Py_Initialize`](https://python-all.ru/3.0/c-api/init.html#Py_Initialize).245246На большинстве систем (в частности, на Unix и Windows, хотя детали немного различаются) [`Py_Initialize`](https://python-all.ru/3.0/c-api/init.html#Py_Initialize) вычисляет путь поиска модулей на основе своего предположения о местоположении исполняемого файла стандартного интерпретатора Python, предполагая, что библиотека Python находится в фиксированном месте относительно исполняемого файла интерпретатора. В частности, он ищет каталог с именем `lib/pythonX.Y` относительно родительского каталога, где находится исполняемый файл с именем `python` в пути поиска команд оболочки (переменная окружения **PATH**).247248Например, если исполняемый файл Python находится в `/usr/local/bin/python`, он предположит, что библиотеки находятся в `/usr/local/lib/pythonX.Y`. (Фактически, этот конкретный путь также является «запасным» местом, используемым, когда ни один исполняемый файл с именем `python` не найден вдоль **PATH**.) Пользователь может переопределить это поведение, установив переменную окружения [**PYTHONHOME**](https://python-all.ru/3.0/using/cmdline.html#envvar-PYTHONHOME), или добавить дополнительные каталоги в начало стандартного пути, установив [**PYTHONPATH**](https://python-all.ru/3.0/using/cmdline.html#envvar-PYTHONPATH).249250Встраивающее приложение может управлять поиском, вызывая `Py_SetProgramName(file)` *до* вызова [`Py_Initialize`](https://python-all.ru/3.0/c-api/init.html#Py_Initialize). Обратите внимание, что [**PYTHONHOME**](https://python-all.ru/3.0/using/cmdline.html#envvar-PYTHONHOME) всё равно переопределяет это, а [**PYTHONPATH**](https://python-all.ru/3.0/using/cmdline.html#envvar-PYTHONPATH) по-прежнему вставляется в начало стандартного пути. Приложение, требующее полного контроля, должно предоставить собственную реализацию [`Py_GetPath`](https://python-all.ru/3.0/c-api/init.html#Py_GetPath), [`Py_GetPrefix`](https://python-all.ru/3.0/c-api/init.html#Py_GetPrefix), [`Py_GetExecPrefix`](https://python-all.ru/3.0/c-api/init.html#Py_GetExecPrefix) и [`Py_GetProgramFullPath`](https://python-all.ru/3.0/c-api/init.html#Py_GetProgramFullPath) (все они определены в `Modules/getpath.c`).251252Иногда желательно «деинициализировать» Python. Например, приложение может захотеть начать заново (сделать ещё один вызов [`Py_Initialize`](https://python-all.ru/3.0/c-api/init.html#Py_Initialize)) или просто завершить использование Python и освободить память, выделенную Python. Это можно сделать, вызвав [`Py_Finalize`](https://python-all.ru/3.0/c-api/init.html#Py_Finalize). Функция [`Py_IsInitialized`](https://python-all.ru/3.0/c-api/init.html#Py_IsInitialized) возвращает true, если Python находится в инициализированном состоянии. Дополнительная информация об этих функциях приведена в следующей главе. Обратите внимание, что [`Py_Finalize`](https://python-all.ru/3.0/c-api/init.html#Py_Finalize) *не* освобождает всю память, выделенную интерпретатором Python, например, память, выделенная расширяющими модулями, в настоящее время не может быть освобождена.253254## Отладочные сборки255256Python может быть собран с несколькими макросами для включения дополнительных проверок интерпретатора и модулей расширения. Эти проверки, как правило, добавляют значительные накладные расходы во время выполнения, поэтому они не включены по умолчанию.257258Полный список различных типов отладочных сборок находится в файле `Misc/SpecialBuilds.txt` в дистрибутиве исходного кода Python. Доступны сборки, поддерживающие трассировку счетчиков ссылок, отладку распределителя памяти или низкоуровневое профилирование основного цикла интерпретатора. В оставшейся части этого раздела будут описаны только наиболее часто используемые сборки.259260Компиляция интерпретатора с определенным макросом `Py_DEBUG` дает то, что обычно называют «отладочной сборкой» Python. `Py_DEBUG` включается в сборке Unix добавлением *--with-pydebug* к команде `configure`. Он также подразумевается наличием макроса `_DEBUG`, не специфичного для Python. Когда `Py_DEBUG` включен в сборке Unix, оптимизация компилятора отключается.261262В дополнение к отладке счётчика ссылок, описанной ниже, выполняются следующие дополнительные проверки:263264- Дополнительные проверки добавлены в распределитель объектов.265- Дополнительные проверки добавлены в синтаксический анализатор и компилятор.266- Проверяются понижающие приведения от широких типов к узким на предмет потери информации.267- В реализации словаря и множества добавлено несколько утверждений. Кроме того, объект множества получает метод `test_c_api()`.268- Проверки корректности входных аргументов добавлены при создании фрейма.269- Память для целых чисел инициализируется известным недопустимым шаблоном для выявления ссылок на неинициализированные разряды.270- Низкоуровневая трассировка и дополнительные проверки исключений добавлены в виртуальную машину времени выполнения.271- Дополнительные проверки добавлены в реализацию области памяти (arena).272- Дополнительная отладка добавлена в модуль thread.273274Могут быть и другие проверки, не упомянутые здесь.275276Определение `Py_TRACE_REFS` включает трассировку ссылок. При его определении поддерживается циклический двусвязный список активных объектов путем добавления двух дополнительных полей к каждому [`PyObject`](https://python-all.ru/3.0/c-api/structures.html#PyObject). Также отслеживаются общие выделения. При выходе выводятся все существующие ссылки. (В интерактивном режиме это происходит после каждого выполненного интерпретатором оператора.) Подразумевается макросом `Py_DEBUG`.277278Пожалуйста, обратитесь к `Misc/SpecialBuilds.txt` в дистрибутиве исходного кода Python для получения более подробной информации.279