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穩定的 ABIPy_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 包括以下專案: