C Стабильность API

Если не указано иное, на C API Python распространяется политика обратной совместимости PEP 387. Большинство изменений в нем совместимы с исходным кодом (обычно это только добавление новых API). Изменение существующего API или удаление API производится только после периода устаревания или для устранения серьезных проблем.

Двоичный интерфейс приложений (ABI) CPython совместим с предыдущими и последними версиями (если они скомпилированы одинаково; см. Платформенные соображения ниже). Таким образом, код, скомпилированный для Python 3.10.0, будет работать на 3.10.8 и наоборот, но для 3.9.x и 3.11.x его нужно будет компилировать отдельно.

Существует два уровня C API с разными ожиданиями стабильности:

  • Unstable API, может изменяться в младших версиях без периода устаревания. В именах он обозначается префиксом PyUnstable.

  • Limited API, совместимый с несколькими минорными версиями. Если определено Py_LIMITED_API, то из Python.h выводится только это подмножество.

Более подробно они рассматриваются ниже.

Имена с символом подчеркивания, такие как _Py_InternalState, являются частными API, которые могут быть изменены без предупреждения даже в релизах патчей. Если вам нужно использовать этот API, обратитесь к CPython developers, чтобы обсудить добавление публичного API для вашего случая использования.

Нестабильный API на языке C

Любой API с префиксом PyUnstable раскрывает детали реализации CPython и может изменяться в каждом минорном выпуске (например, с 3.9 до 3.10) без каких-либо предупреждений об устаревании. Однако он не будет меняться в релизах с исправлениями (например, с 3.10.0 на 3.10.1).

Обычно он предназначен для специализированных низкоуровневых инструментов, таких как отладчики.

От проектов, использующих этот API, ожидается, что они будут следить за развитием CPython и тратить дополнительные усилия на адаптацию к изменениям.

Стабильный двоичный интерфейс приложения

Для простоты в этом документе говорится о расширениях, но Limited API и Stable ABI работают одинаково для всех случаев использования API - например, для встраивания Python.

Ограниченный C API

В Python 3.2 появился Limited API, подмножество API Python на языке C. Расширения, использующие только Limited API, могут быть скомпилированы один раз и работать с несколькими версиями Python. Содержимое Limited API - listed below.

Py_LIMITED_API

Определите этот макрос перед включением Python.h, чтобы разрешить использование только Limited API и выбрать версию Limited API.

Определите значение Py_LIMITED_API равным значению PY_VERSION_HEX, соответствующему самой низкой версии Python, которую поддерживает ваше расширение. Расширение будет работать без перекомпиляции со всеми версиями Python 3, начиная с указанной, и сможет использовать Limited API, представленные до этой версии.

Вместо того чтобы использовать макрос PY_VERSION_HEX напрямую, задайте минимальную минорную версию (например, 0x030A0000 для Python 3.10) для стабильности при компиляции с будущими версиями Python.

Вы также можете определить Py_LIMITED_API в 3. Это работает так же, как и 0x03020000 (Python 3.2, версия, в которой появился Limited API).

Стабильный ABI

Для этого Python предоставляет Стабильный ABI: набор символов, которые остаются совместимыми во всех версиях Python 3.x.

Стабильный ABI содержит символы, раскрытые в Limited API, но также и другие - например, функции, необходимые для поддержки старых версий Limited API.

В Windows расширения, использующие Stable ABI, должны быть скомпонованы с python3.dll, а не с библиотекой, специфичной для конкретной версии, такой как python39.dll.

На некоторых платформах Python будет искать и загружать файлы общих библиотек с именем abi3 (например, mymodule.abi3.so). Он не проверяет, соответствуют ли такие расширения стабильному ABI. Пользователю (или его средствам упаковки) необходимо убедиться, что, например, расширения, созданные с использованием 3.10+ Limited API, не будут установлены для более низких версий Python.

Все функции в Stable ABI присутствуют как функции в общей библиотеке Python, а не только как макросы. Это делает их пригодными для использования из языков, не использующих препроцессор C.

Ограниченный объем и производительность API

Цель ограниченного API - позволить все то, что возможно в полном C API, но, возможно, со снижением производительности.

Например, если функция PyList_GetItem() доступна, то ее «небезопасный» вариант макроса PyList_GET_ITEM() - нет. Макрос может быть быстрее, потому что он может полагаться на детали реализации объекта списка, зависящие от версии.

Если Py_LIMITED_API не определена, некоторые функции C API инлайнятся или заменяются макросами. Определение Py_LIMITED_API отключает эту инкрустацию, обеспечивая стабильность по мере совершенствования структур данных Python, но, возможно, снижая производительность.

Отказавшись от определения Py_LIMITED_API, можно скомпилировать расширение Limited API с ABI для конкретной версии. Это может повысить производительность для данной версии Python, но ограничит совместимость. Компиляция с использованием Py_LIMITED_API позволит получить расширение, которое можно распространять там, где нет конкретной версии - например, в пререлизах грядущей версии Python.

Оговорки об ограниченном API

Обратите внимание, что компиляция с помощью Py_LIMITED_API не является полной гарантией того, что код соответствует Limited API или Stable ABI. Py_LIMITED_API охватывает только определения, но API включает и другие вопросы, такие как ожидаемая семантика.

Одна из проблем, от которой не защищает Py_LIMITED_API, - вызов функции с аргументами, которые недопустимы в более низкой версии Python. Например, рассмотрим функцию, которая начинает принимать в качестве аргумента NULL. В Python 3.9 NULL теперь выбирает поведение по умолчанию, но в Python 3.8 аргумент будет использован напрямую, что приведет к разыменованию NULL и краху. Аналогичный аргумент работает для полей структур.

Другая проблема заключается в том, что некоторые поля struct в настоящее время не скрываются при определении Py_LIMITED_API, хотя они являются частью Limited API.

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

Мы также рекомендуем изучить документацию по всем используемым API, чтобы проверить, не является ли оно явной частью Limited API. Даже при определении Py_LIMITED_API несколько приватных объявлений будут открыты по техническим причинам (или даже непреднамеренно, как ошибки).

Также обратите внимание, что Limited API не обязательно стабилен: компиляция с Py_LIMITED_API в Python 3.8 означает, что расширение будет работать в Python 3.12, но оно не обязательно будет компилироваться в Python 3.12. В частности, части Limited API могут быть устаревшими и удаленными, при условии, что стабильный ABI останется стабильным.

Платформенные соображения

Стабильность ABI зависит не только от Python, но и от используемого компилятора, библиотек нижнего уровня и опций компилятора. Для целей Stable ABI эти детали определяют «платформу». Обычно они зависят от типа ОС и архитектуры процессора

Каждый конкретный распространитель Python несет ответственность за то, чтобы все версии Python на конкретной платформе были собраны таким образом, чтобы не нарушать Stable ABI. Так обстоит дело с выпусками для Windows и macOS от python.org и многих сторонних распространителей.

Содержание ограниченного API

В настоящее время Limited API включает в себя следующие элементы: