Стабильность C API¶
На C API Python распространяется политика обратной совместимости PEP 387. Хотя C API будет меняться с каждым новым выпуском (например, с 3.9 по 3.10), большинство изменений будут совместимы с исходным кодом, как правило, путем добавления только нового API. Изменение существующего API или удаление API производится только по истечении периода амортизации или для устранения серьезных неполадок.
Двоичный интерфейс приложений CPython (ABI) поддерживает прямую и обратную совместимость во всех младших версиях (если они скомпилированы одинаково; смотрите Соображения, касающиеся платформы ниже). Итак, код, скомпилированный для Python 3.10.0, будет работать на 3.10.8 и наоборот, но его нужно будет скомпилировать отдельно для 3.9.x и 3.11.x.
Имена, перед которыми ставится знак подчеркивания, например _Py_InternalState
, являются частными API, которые могут изменяться без предварительного уведомления даже в выпусках исправлений.
Стабильный двоичный интерфейс приложения¶
Для простоты в этом документе говорится о расширениях, но ограниченный API и стабильный ABI работают одинаково для всех применений API – например, для встраивания Python.
Ограниченный C API¶
В Python 3.2 появился Limited API, подмножество C API Python. Расширения, которые используют только Limited API, могут быть скомпилированы один раз и работать с несколькими версиями Python. Содержимое Limited API listed below.
-
Py_LIMITED_API¶
Определите этот макрос перед включением
Python.h
, чтобы выбрать использование только ограниченного API и выбрать версию API с ограниченным доступом.Определите для
Py_LIMITED_API
значениеPY_VERSION_HEX
, соответствующее самой низкой версии Python, поддерживаемой вашим расширением. Расширение будет работать без перекомпиляции со всеми версиями Python 3, начиная с указанной, и может использовать ограниченный API, введенный до этой версии.Вместо того, чтобы напрямую использовать макрос
PY_VERSION_HEX
, жестко запрограммируйте минимальную младшую версию (например,0x030A0000
для Python 3.10) для обеспечения стабильности при компиляции с будущими версиями Python.Вы также можете задать для
Py_LIMITED_API
значение3
. Это работает так же, как и для0x03020000
(Python 3.2, версия, в которой представлен ограниченный API).
Стабильный АБИ¶
Чтобы включить это, Python предоставляет Стабильный ABI: набор символов, которые будут оставаться совместимыми во всех версиях Python 3.x.
Стабильный ABI содержит символы, отображаемые в Limited API, а также другие – например, функции, необходимые для поддержки старых версий ограниченного API.
В Windows расширения, использующие стабильный ABI, должны быть связаны с python3.dll
, а не с библиотекой, зависящей от версии, такой как python39.dll
.
На некоторых платформах Python будет искать и загружать файлы общей библиотеки с именами, указанными в теге abi3
(например, mymodule.abi3.so
). Он не проверяет, соответствуют ли такие расширения стабильному ABI. Пользователь (или его инструменты упаковки) должны убедиться, что, например, расширения, созданные с использованием API с ограниченным использованием версии 3.10+, не установлены для более ранних версий Python.
Все функции в стабильном ABI представлены как функции в общей библиотеке Python, а не только как макросы. Это позволяет использовать их в языках, которые не используют препроцессор C.
Ограниченный объем и производительность API¶
Цель ограниченного API состоит в том, чтобы разрешить все, что возможно с полным C API, но, возможно, с уменьшением производительности.
Например, в то время как PyList_GetItem()
доступен, его “небезопасный” вариант макроса PyList_GET_ITEM()
недоступен. Макрос может работать быстрее, поскольку он может полагаться на детали реализации объекта list, зависящие от версии.
Без определения Py_LIMITED_API
некоторые функции C API встраиваются или заменяются макросами. Определение Py_LIMITED_API
отключает это встраивание, обеспечивая стабильность по мере улучшения структур данных Python, но, возможно, снижая производительность.
Исключив определение Py_LIMITED_API
, можно скомпилировать ограниченное расширение 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
и сбою. Аналогичный аргумент работает для полей структур.
Другая проблема заключается в том, что некоторые структурные поля в настоящее время не скрыты при определении Py_LIMITED_API
, даже если они являются частью ограниченного API.
По этим причинам мы рекомендуем протестировать расширение со всеми второстепенными версиями Python, которые оно поддерживает, и предпочтительно создавать его с самой низкой версией.
Мы также рекомендуем ознакомиться с документацией по всем используемым API, чтобы проверить, является ли он явной частью API с ограниченным доступом. Даже если определено Py_LIMITED_API
, некоторые частные объявления отображаются по техническим причинам (или даже непреднамеренно, как ошибки).
Также обратите внимание, что ограниченный API не обязательно стабилен: компиляция с Py_LIMITED_API
с Python 3.8 означает, что расширение будет работать с Python 3.12, но оно не обязательно будет компилироваться с Python 3.12. В частности, некоторые части ограниченного API могут быть признаны устаревшими и удалены при условии, что стабильный ABI останется стабильным.
Соображения, касающиеся платформы¶
Стабильность ABI зависит не только от Python, но и от используемого компилятора, библиотек более низкого уровня и опций компилятора. Для целей Stable ABI эти детали определяют “платформу”. Обычно они зависят от типа операционной системы и архитектуры процессора
Каждый конкретный распространитель Python несет ответственность за то, чтобы все версии Python на конкретной платформе были созданы таким образом, чтобы не нарушать стабильный ABI. Это относится к версиям Windows и Mac OS от python.org
и многих сторонних распространителей.
Содержимое ограниченного API¶
В настоящее время Limited API включает в себя следующие элементы:
PyBaseObject_Type
PyByteArrayIter_Type
PyBytesIter_Type
PyBytes_DecodeEscape()
PyBytes_Repr()
PyCFunction_Call()
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()
PyEval_CallFunction()
PyEval_CallMethod()
PyEval_CallObjectWithKeywords()
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_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
PySys_HasWarnOptions()
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_InternImmortal()
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
getter
setter
ssizessizeargfunc
ssizessizeobjargproc
symtable