C API 穩定性¶
除非另有說明,Python 的 C API 受PEP 387 向後相容性策略的約束。對它的大多數更改都是原始碼相容的(通常僅透過新增新的 API)。更改現有 API 或刪除 API 僅在棄用期後或為了解決嚴重問題時進行。
CPython 的應用程式二進位制介面(ABI)在小版本之間是向前和向後相容的(如果它們以相同的方式編譯;請參閱下面的平臺注意事項)。因此,為 Python 3.10.0 編譯的程式碼可以在 3.10.8 上工作,反之亦然,但需要為 3.9.x 和 3.11.x 單獨編譯。
C API 有兩個層級,具有不同的穩定性期望:
不穩定的 API,可能會在小版本中更改,而無需棄用期。它在名稱中以
PyUnstable
字首標記。有限的 API,在多個小版本之間相容。定義
Py_LIMITED_API
時,只有此子集從Python.h
中公開。
下面將更詳細地討論這些內容。
以下劃線開頭的名稱,例如 _Py_InternalState
,是私有 API,即使在補丁版本中也可能在不通知的情況下更改。如果您需要使用此 API,請考慮聯絡 CPython 開發人員,討論為您的用例新增公共 API。
不穩定的 C API¶
任何以 PyUnstable
字首命名的 API 都會暴露 CPython 的實現細節,並且可能會在每個小版本(例如,從 3.9 到 3.10)中更改,而沒有任何棄用警告。但是,它不會在錯誤修復版本中更改(例如,從 3.10.0 到 3.10.1)。
它通常用於專門的、低階的工具,如偵錯程式。
使用此 API 的專案應遵循 CPython 開發並花費額外的精力來適應更改。
穩定的應用程式二進位制介面¶
為簡單起見,本文件討論的是*擴充套件*,但有限的 API 和穩定的 ABI 對於 API 的所有用途(例如,嵌入 Python)都以相同的方式工作。
有限的 C API¶
Python 3.2 引入了*有限的 API*,它是 Python C API 的一個子集。僅使用有限的 API 的擴充套件可以編譯一次並在多個 Python 版本上載入。有限的 API 的內容在下面列出。
-
Py_LIMITED_API¶
在包含
Python.h
之前定義此宏,以選擇僅使用有限的 API,並選擇有限的 API 版本。將
Py_LIMITED_API
定義為與您的擴充套件支援的最低 Python 版本對應的PY_VERSION_HEX
的值。該擴充套件將與從指定的版本開始的所有 Python 3 版本實現 ABI 相容,並且可以使用該版本之前引入的有限的 API。為了在將來使用 Python 版本進行編譯時保持穩定性,不要直接使用
PY_VERSION_HEX
宏,而是硬編碼一個最小的小版本(例如,Python 3.10 的0x030A0000
)。您還可以將
Py_LIMITED_API
定義為3
。這與0x03020000
(Python 3.2,引入有限的 API 的版本)的工作方式相同。
穩定的 ABI¶
為了實現此目的,Python 提供了一個*穩定的 ABI*:一組在 Python 3.x 版本中保持 ABI 相容的符號。
注意
穩定的 ABI 可以防止 ABI 問題,例如由於缺少符號導致的連結器錯誤或由於結構佈局或函式簽名更改導致的資料損壞。但是,Python 中的其他更改可能會更改擴充套件的*行為*。有關詳細資訊,請參閱 Python 的向後相容性策略(PEP 387)。
穩定的 ABI 包含在有限的 API中公開的符號,但也包含其他符號 – 例如,支援舊版本的有限的 API 所必需的函式。
在 Windows 上,使用穩定 ABI 的擴充套件應連結到 python3.dll
而不是版本特定的庫,如 python39.dll
。
在某些平臺上,Python 將查詢並載入使用 abi3
標記命名的共享庫檔案(例如 mymodule.abi3.so
)。它不檢查此類擴充套件是否符合穩定的 ABI。使用者(或他們的打包工具)需要確保,例如,使用 3.10+ 有限 API 構建的擴充套件不會安裝到較低版本的 Python 中。
穩定的 ABI 中的所有函式都作為 Python 共享庫中的函式存在,而不僅僅是作為宏。這使得它們可以從不使用 C 預處理器的語言中使用。
有限的 API 範圍和效能¶
有限的 API 的目標是允許使用完整的 C API 完成所有事情,但可能會有效能損失。
例如,雖然 PyList_GetItem()
可用,但其“不安全”的宏變體 PyList_GET_ITEM()
不可用。宏可以更快,因為它依賴於列表物件的版本特定實現細節。
在未定義 Py_LIMITED_API
的情況下,某些 C API 函式會被內聯或替換為宏。定義 Py_LIMITED_API
會停用此內聯,從而在改進 Python 的資料結構時允許穩定性,但可能會降低效能。
透過省略 Py_LIMITED_API
定義,可以使用版本特定的 ABI 編譯有限的 API 擴充套件。這可以提高該 Python 版本的效能,但會限制相容性。然後使用 Py_LIMITED_API
進行編譯將生成一個可在版本特定的擴充套件不可用的情況下分發的擴充套件 – 例如,對於即將釋出的 Python 版本的預發行版。
有限的 API 注意事項¶
請注意,使用 Py_LIMITED_API
進行編譯*不能*完全保證程式碼符合有限的 API或穩定的 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
,出於技術原因(甚至可能是意外的 bug),也會公開一些私有宣告。
另請注意,有限的 API 不一定穩定:使用 Python 3.8 中的 Py_LIMITED_API
進行編譯意味著擴充套件將與 Python 3.12 一起執行,但不一定會使用 Python 3.12 進行*編譯*。特別是,有限 API 的某些部分可能會被棄用和刪除,前提是穩定的 ABI 保持穩定。
平臺注意事項¶
ABI 穩定性不僅取決於 Python,還取決於所使用的編譯器、底層庫和編譯器選項。 對於穩定 ABI,這些細節定義了一個“平臺”。 它們通常取決於作業系統型別和處理器架構。
每個特定的 Python 發行商都有責任確保特定平臺上的所有 Python 版本都以不破壞穩定 ABI 的方式構建。 python.org
上的 Windows 和 macOS 版本以及許多第三方發行商都是這種情況。
有限 API 的內容¶
目前,有限 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_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
PyMap_Type
PyMemberDescr_Type
PyMemoryView_Type
PyMethodDescr_Type
PyModuleDef_Base
PyModuleDef_Type
PyOS_InterruptOccurred()
PyOS_mystricmp()
PyOS_mystrnicmp()
PyObject_DelItemString()
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