Following system colour scheme - Python 增強提案 Selected dark colour scheme - Python 增強提案 Selected light colour scheme - Python 增強提案

Python 增強提案

PEP 399 – 純Python/C加速器模組相容性要求

作者:
Brett Cannon <brett at python.org>
狀態:
最終版
型別:
資訊性
建立日期:
2011年4月4日
Python 版本:
3.3
釋出歷史:
2011年4月4日,2011年4月12日,2011年7月17日,2011年8月15日,2013年1月1日

目錄

摘要

CPython下的Python標準庫包含多種模組例項,這些模組既有純Python實現,也有C語言實現(完全或部分)。本PEP要求,在這些情況下,C語言程式碼必須透過用於純Python程式碼的測試套件,以便儘可能地作為即插即用替代品(C語言和VM特定測試除外)。此外,還要求新的、缺乏純Python等效實現的基於C語言的模組,需獲得特別許可才能新增到標準庫中。

基本原理

Python已經超越了CPython虛擬機器(VM)。IronPythonJythonPyPy目前都是CPython VM的有效替代品。圍繞Python程式語言形成的VM生態系統使得Python被用於CPython無法使用的許多不同領域,例如,Jython允許Python在Java應用程式中使用。

除了CPython之外,所有虛擬機器都面臨一個問題,即如何處理標準庫中(在某種程度上)用C語言實現的模組。由於其他虛擬機器通常不支援CPython的完整C API,它們無法使用用於建立模組的程式碼。這常常導致這些其他虛擬機器要麼用純Python重新實現模組,要麼用實現虛擬機器本身的程式語言(例如,IronPython使用C#)重新實現。CPython、PyPy、Jython和IronPython之間的這種重複工作是極其不幸的,因為至少用純Python實現模組將有助於減輕這種重複工作。

本PEP的目的是透過規定所有新增到Python標準庫的新模組必須具有純Python實現,除非獲得特殊豁免,從而最大限度地減少這種重複工作。這確保了標準庫中的模組對所有虛擬機器都可用,而不僅僅是CPython(不符合此要求的現有模組是豁免的,儘管沒有人阻止人們追溯性地新增純Python實現)。

出於效能原因,允許用C語言重新實現模組的部分(或全部)(在CPython的情況下),但任何此類加速程式碼都必須透過相同的測試套件(不包括VM或C特定的測試)以驗證語義並防止差異。為此,在新增加速程式碼之前,模組的測試套件必須對純Python實現進行全面的覆蓋。

詳情

從Python 3.3開始,任何新增到標準庫的模組都必須有純Python實現。只有在Python開發團隊對該模組給予特殊豁免時,才能忽略此規則。通常,豁免只在模組封裝了特定的C語言庫時(例如,sqlite3)才會授予。在授予豁免時,該模組將被視為CPython獨有,不屬於其他虛擬機器應支援的Python標準庫的一部分。使用ctypes來為C庫提供API將繼續受到反對,因為ctypes缺乏C程式碼通常依賴的編譯器保證,以防止某些錯誤發生(例如,API更改)。

儘管本PEP規定必須有純Python實現,但這並不排除使用配套的加速模組。如果提供了加速模組,其名稱應與被加速的模組相同,並帶有一個下劃線作為字首,例如,warnings的加速模組名為_warnings。從純Python實現訪問加速程式碼的常見模式是使用import *匯入,例如,from _warnings import *。這通常在模組的末尾完成,以允許它用其加速的等效項覆蓋特定的Python物件。這種匯入也可以在模組末尾之前完成,例如,提供了加速基類,然後由Python程式碼進行子類化。本PEP不強制標準庫中缺乏純Python等效項的現有模組獲得此類模組。但如果有人自願提供和維護純Python等效項(例如,PyPy團隊自願提供其csv模組的純Python實現並維護它),那麼此類程式碼將被接受。在這些情況下,C版本被認為是預期語義的參考實現。

任何新的加速程式碼都必須儘可能地作為純Python實現的即插即用替代品。提供加速程式碼的VM的技術細節允許在必要時有所不同,例如,在C中實現時,一個類可以是type。為了驗證Python和等效C程式碼的操作儘可能相似,兩個程式碼庫都必須使用適用於純Python程式碼的相同測試進行測試(特定於C程式碼或任何VM的測試不屬於此要求)。測試套件預計會很廣泛,以驗證預期的語義。

作為即插即用替代品還規定,加速程式碼中不得提供純Python程式碼中不存在的公共API。如果沒有此要求,人們可能會意外地依賴加速程式碼中的某個細節,而其他使用純Python實現的VM則無法獲得該細節。為了幫助驗證語義等效性契約得到滿足,模組必須在有加速程式碼和沒有加速程式碼的情況下儘可能徹底地進行測試。

例如,要編寫同時測試模組的純Python版本和C加速版本的測試,可以遵循一個基本範例:

from test.support import import_fresh_module
import unittest

c_heapq = import_fresh_module('heapq', fresh=['_heapq'])
py_heapq = import_fresh_module('heapq', blocked=['_heapq'])


class ExampleTest:

    def test_example(self):
        self.assertTrue(hasattr(self.module, 'heapify'))


class PyExampleTest(ExampleTest, unittest.TestCase):
    module = py_heapq


@unittest.skipUnless(c_heapq, 'requires the C _heapq module')
class CExampleTest(ExampleTest, unittest.TestCase):
    module = c_heapq


if __name__ == '__main__':
    unittest.main()

測試模組定義了一個基類(ExampleTest),其中包含透過self.heapq類屬性訪問heapq模組的測試方法,以及兩個子類,它們將此屬性設定為模組的Python版本或C版本。請注意,只有這兩個子類繼承自unittest.TestCase——這可以防止unittest測試發現將ExampleTest類檢測為TestCase子類。可以在測試C程式碼的類中新增skipUnless裝飾器,以便在C模組不可用時跳過這些測試。

如果此測試為純Python實現中的heapq.heappop()提供了廣泛的覆蓋,則允許將加速C程式碼新增到CPython的標準庫中。如果未能提供,則需要更新測試套件,直到提供適當的覆蓋範圍,然後才能新增加速C程式碼。

為了也有助於相容性,C程式碼應該在物件上使用抽象API,以防止意外地依賴特定型別。例如,如果一個函式接受一個序列,那麼C程式碼應該預設使用PyObject_GetItem()而不是像PyList_GetItem()這樣的東西。如果使用了適當的PyList_CheckExact(),則C程式碼允許有快速路徑,但否則API應該適用於任何“鴨子型別”為適當介面而不是特定型別的物件。


來源:https://github.com/python/peps/blob/main/peps/pep-0399.rst

最後修改:2025-02-01 08:59:27 GMT