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 включает в себя следующие элементы:
PyBaseObject_Type
PyByteArrayIter_Type
PyBytesIter_Type
PyBytes_DecodeEscape()
PyBytes_Repr()
PyCFunction_GetFlags()
PyCFunction_GetFunction()
PyCFunction_GetSelf()
PyCFunction_Type
PyCapsule_Type
PyClassMethodDescr_Type
PyDictItems_Type
PyDictIterItem_Type
PyDictIterKey_Type
PyDictIterValue_Type
PyDictKeys_Type
PyDictProxy_Type
PyDictRevIterItem_Type
PyDictRevIterKey_Type
PyDictRevIterValue_Type
PyDictValues_Type
PyEllipsis_Type
PyEnum_Type
PyErr_Display()
PyErr_ProgramText()
PyExc_ArithmeticError
PyExc_AssertionError
PyExc_AttributeError
PyExc_BaseException
PyExc_BaseExceptionGroup
PyExc_BlockingIOError
PyExc_BrokenPipeError
PyExc_BufferError
PyExc_BytesWarning
PyExc_ChildProcessError
PyExc_ConnectionAbortedError
PyExc_ConnectionError
PyExc_ConnectionRefusedError
PyExc_ConnectionResetError
PyExc_DeprecationWarning
PyExc_EOFError
PyExc_EncodingWarning
PyExc_EnvironmentError
PyExc_Exception
PyExc_FileExistsError
PyExc_FileNotFoundError
PyExc_FloatingPointError
PyExc_FutureWarning
PyExc_GeneratorExit
PyExc_IOError
PyExc_ImportError
PyExc_ImportWarning
PyExc_IncompleteInputError
PyExc_IndentationError
PyExc_IndexError
PyExc_InterruptedError
PyExc_IsADirectoryError
PyExc_KeyError
PyExc_KeyboardInterrupt
PyExc_LookupError
PyExc_MemoryError
PyExc_ModuleNotFoundError
PyExc_NameError
PyExc_NotADirectoryError
PyExc_NotImplementedError
PyExc_OSError
PyExc_OverflowError
PyExc_PendingDeprecationWarning
PyExc_PermissionError
PyExc_ProcessLookupError
PyExc_RecursionError
PyExc_ReferenceError
PyExc_ResourceWarning
PyExc_RuntimeError
PyExc_RuntimeWarning
PyExc_StopAsyncIteration
PyExc_StopIteration
PyExc_SyntaxError
PyExc_SyntaxWarning
PyExc_SystemError
PyExc_SystemExit
PyExc_TabError
PyExc_TimeoutError
PyExc_TypeError
PyExc_UnboundLocalError
PyExc_UnicodeDecodeError
PyExc_UnicodeEncodeError
PyExc_UnicodeError
PyExc_UnicodeTranslateError
PyExc_UnicodeWarning
PyExc_UserWarning
PyExc_ValueError
PyExc_Warning
PyExc_WindowsError
PyExc_ZeroDivisionError
PyExceptionClass_Name()
PyFilter_Type
PyGILState_STATE
PyGetSetDescr_Type
PyListIter_Type
PyListRevIter_Type
PyLongRangeIter_Type
PyLong_GetInfo()
PyMap_Type
PyMemberDescr_Type
PyMemoryView_Type
PyMethodDescr_Type
PyModuleDef_Base
PyModuleDef_Type
PyOS_InterruptOccurred()
PyOS_mystricmp()
PyOS_mystrnicmp()
PyObject_DelItemString()
PyObject_SelfIter()
PyRangeIter_Type
PyRange_Type
PyReversed_Type
PySequence_In()
PySetIter_Type
PySuper_Type
PyThread_GetInfo()
PyThread_acquire_lock()
PyThread_acquire_lock_timed()
PyThread_allocate_lock()
PyThread_exit_thread()
PyThread_free_lock()
PyThread_get_stacksize()
PyThread_get_thread_ident()
PyThread_get_thread_native_id()
PyThread_init_thread()
PyThread_release_lock()
PyThread_set_stacksize()
PyThread_start_new_thread()
PyTraceBack_Here()
PyTraceBack_Print()
PyTraceBack_Type
PyTupleIter_Type
PyUnicodeIter_Type
PyUnicode_Append()
PyUnicode_AppendAndDel()
PyUnicode_AsDecodedObject()
PyUnicode_AsDecodedUnicode()
PyUnicode_AsEncodedObject()
PyUnicode_AsEncodedUnicode()
PyUnicode_BuildEncodingMap()
PyUnicode_DecodeCodePageStateful()
PyUnicode_FromOrdinal()
PyUnicode_GetDefaultEncoding()
PyUnicode_Partition()
PyUnicode_RPartition()
PyUnicode_RSplit()
PyUnicode_Resize()
PyVarObject.ob_base
PyWeakReference
PyWrapperDescr_Type
PyZip_Type
Py_FileSystemDefaultEncodeErrors
Py_FileSystemDefaultEncoding
Py_GetRecursionLimit()
Py_HasFileSystemDefaultEncoding
Py_MakePendingCalls()
Py_SetRecursionLimit()
Py_UTF8Mode
Py_intptr_t
Py_uintptr_t
ssizessizeargfunc
ssizessizeobjargproc
symtable