Python 3.12 中的新特性

編輯:

Adam Turner

本文解釋了 Python 3.12 相對於 3.11 的新功能。Python 3.12 於 2023 年 10 月 2 日釋出。有關完整詳細資訊,請參閱更新日誌

參見

PEP 693 – Python 3.12 釋出日程

摘要 – 釋出亮點

Python 3.12 是 Python 程式語言的一個穩定版本,其中包含對語言和標準庫的各種更改。庫的更改側重於清理已棄用的 API、可用性和正確性。值得注意的是,distutils 包已從標準庫中刪除。ospathlib 中的檔案系統支援有許多改進,並且有幾個模組的效能更好。

語言的更改側重於可用性,因為 f-strings 已刪除了許多限制,“你的意思是……”建議也持續改進。新的型別引數語法type 語句改善了與靜態型別檢查器一起使用泛型型別類型別名的人機工程學。

本文不試圖提供所有新功能的完整規範,而是提供一個方便的概述。有關完整詳細資訊,您應參閱文件,例如庫參考語言參考。如果您想了解更改的完整實現和設計原理,請參閱特定新功能的 PEP;但請注意,一旦功能完全實現,PEP 通常不會保持最新。


新語法功能

新語法特性

直譯器的改進

Python 資料模型改進

標準庫的重大改進

安全改進

  • 將內建 hashlib 的 SHA1、SHA3、SHA2-384、SHA2-512 和 MD5 實現替換為來自 HACL* 專案的經過形式驗證的程式碼。這些內建實現仍作為僅當 OpenSSL 不提供時才使用的回退。

C API 的改進

CPython 實現改進

  • PEP 709,推導式內聯

  • Linux perf 分析器CPython 支援

  • 在支援的平臺上實現棧溢位保護

新的型別特性

重要棄用、刪除或限制

  • PEP 623:從 Python 的 C API 中的 Unicode 物件中刪除 wstr,將每個 str 物件的大小至少減少 8 位元組。

  • PEP 632:刪除 distutils 包。有關替換其提供的 API 的建議,請參閱遷移指南。如果您在 Python 3.12 及更高版本中仍然需要 distutils,第三方 Setuptools 包會繼續提供它。

  • gh-95299:不要在用 venv 建立的虛擬環境中預安裝 setuptools。這意味著 distutilssetuptoolspkg_resourceseasy_install 將不再預設可用;要訪問這些,請在已啟用的虛擬環境中執行 pip install setuptools

  • asynchatasyncoreimp 模組已刪除,以及幾個 unittest.TestCase 方法別名

新功能

PEP 695:型別引數語法

PEP 484 下的泛型類和函式使用冗長的語法宣告,使得型別引數的範圍不明確,並需要顯式宣告方差。

PEP 695 引入了一種新的、更緊湊和明確的方式來建立泛型類函式

def max[T](args: Iterable[T]) -> T:
    ...

class list[T]:
    def __getitem__(self, index: int, /) -> T:
        ...

    def append(self, element: T) -> None:
        ...

此外,PEP 引入了一種使用 type 語句宣告類型別名的新方式,它建立了一個 TypeAliasType 例項

type Point = tuple[float, float]

類型別名也可以是泛型的

type Point[T] = tuple[T, T]

新語法允許宣告 TypeVarTupleParamSpec 引數,以及帶有限制或約束的 TypeVar 引數

type IntFunc[**P] = Callable[P, int]  # ParamSpec
type LabeledTuple[*Ts] = tuple[str, *Ts]  # TypeVarTuple
type HashableSequence[T: Hashable] = Sequence[T]  # TypeVar with bound
type IntOrStrSequence[T: (int, str)] = Sequence[T]  # TypeVar with constraints

透過此語法建立的類型別名的值以及型別變數的界限和約束僅在需要時進行評估(請參閱惰性評估)。這意味著類型別名可以引用檔案中稍後定義的其他型別。

透過型別引數列表宣告的型別引數在聲明範圍和任何巢狀範圍中可見,但在外部範圍中不可見。例如,它們可以用於泛型類的方法的型別註釋或類體中。但是,它們不能在類定義後在模組範圍中使用。有關型別引數執行時語義的詳細說明,請參閱型別引數列表

為了支援這些作用域語義,引入了一種新的作用域,即註釋作用域。註釋作用域在大多數情況下表現得像函式作用域,但與封閉的類作用域的互動方式不同。在 Python 3.13 中,註釋也將透過註釋作用域進行評估。

有關更多詳細資訊,請參閱PEP 695

(PEP 由 Eric Traut 撰寫。由 Jelle Zijlstra、Eric Traut 和其他人實現在 gh-103764 中。)

PEP 701:f-string 的句法形式化

PEP 701 解除了一些對 f-strings 使用的限制。f-string 內的表示式元件現在可以是任何有效的 Python 表示式,包括重用與包含 f-string 相同引號的字串、多行表示式、註釋、反斜槓和 Unicode 轉義序列。讓我們詳細介紹這些內容

  • 引號重用:在 Python 3.11 中,重用與包含 f-string 相同的引號會引發 SyntaxError,強制使用者使用其他可用引號(例如,如果 f-string 使用單引號,則使用雙引號或三引號)。在 Python 3.12 中,您現在可以執行以下操作

    >>> songs = ['Take me back to Eden', 'Alkaline', 'Ascensionism']
    >>> f"This is the playlist: {", ".join(songs)}"
    'This is the playlist: Take me back to Eden, Alkaline, Ascensionism'
    

    請注意,在此更改之前,f-string 的巢狀方式沒有明確限制,但字串引號不能在 f-string 的表示式元件內重用這一事實使得任意巢狀 f-string 變得不可能。實際上,這是可以編寫的最深層巢狀的 f-string

    >>> f"""{f'''{f'{f"{1+1}"}'}'''}"""
    '2'
    

    由於現在 f-string 可以在表示式元件內包含任何有效的 Python 表示式,因此現在可以任意巢狀 f-string

    >>> f"{f"{f"{f"{f"{f"{1+1}"}"}"}"}"}"
    '2'
    
  • 多行表示式和註釋:在 Python 3.11 中,f-string 表示式必須定義在單行中,即使 f-string 中的表示式通常可以跨多行(例如,在多行上定義的字面量列表),這使得它們更難閱讀。在 Python 3.12 中,您現在可以定義跨多行的 f-string,並新增行內註釋

    >>> f"This is the playlist: {", ".join([
    ...     'Take me back to Eden',  # My, my, those eyes like fire
    ...     'Alkaline',              # Not acid nor alkaline
    ...     'Ascensionism'           # Take to the broken skies at last
    ... ])}"
    'This is the playlist: Take me back to Eden, Alkaline, Ascensionism'
    
  • 反斜槓和 Unicode 字元:在 Python 3.12 之前,f-string 表示式不能包含任何 \ 字元。這也影響了 Unicode 轉義序列(例如 \N{snowman}),因為這些序列包含以前不能成為 f-string 表示式元件一部分的 \N 部分。現在,您可以定義如下表達式

    >>> print(f"This is the playlist: {"\n".join(songs)}")
    This is the playlist: Take me back to Eden
    Alkaline
    Ascensionism
    >>> print(f"This is the playlist: {"\N{BLACK HEART SUIT}".join(songs)}")
    This is the playlist: Take me back to Eden♥Alkaline♥Ascensionism
    

有關更多詳細資訊,請參閱PEP 701

由於此功能實現方式的積極副作用(透過使用PEG 解析器解析 f-strings),現在 f-string 的錯誤訊息更精確,幷包含錯誤的精確位置。例如,在 Python 3.11 中,以下 f-string 會引發 SyntaxError

>>> my_string = f"{x z y}" + f"{1 + 1}"
  File "<stdin>", line 1
    (x z y)
     ^^^
SyntaxError: f-string: invalid syntax. Perhaps you forgot a comma?

但是錯誤訊息不包含行內錯誤的精確位置,並且表示式被人為地用括號括起來。在 Python 3.12 中,由於 f-strings 是用 PEG 解析器解析的,錯誤訊息可以更精確並顯示整行

>>> my_string = f"{x z y}" + f"{1 + 1}"
  File "<stdin>", line 1
    my_string = f"{x z y}" + f"{1 + 1}"
                   ^^^
SyntaxError: invalid syntax. Perhaps you forgot a comma?

(由 Pablo Galindo、Batuhan Taskaya、Lysandros Nikolaou、Cristián Maureira-Fredes 和 Marta Gómez 在 gh-102856 中貢獻。PEP 由 Pablo Galindo、Batuhan Taskaya、Lysandros Nikolaou 和 Marta Gómez 撰寫)。

PEP 684:每個直譯器一個 GIL

PEP 684 引入了每個直譯器一個 GIL,因此子直譯器現在可以為每個直譯器建立唯一的 GIL。這允許 Python 程式充分利用多個 CPU 核心。目前這僅透過 C-API 提供,儘管 預計 3.13 將提供 Python API

使用新的 Py_NewInterpreterFromConfig() 函式建立具有自己 GIL 的直譯器

PyInterpreterConfig config = {
    .check_multi_interp_extensions = 1,
    .gil = PyInterpreterConfig_OWN_GIL,
};
PyThreadState *tstate = NULL;
PyStatus status = Py_NewInterpreterFromConfig(&tstate, &config);
if (PyStatus_Exception(status)) {
    return -1;
}
/* The new interpreter is now active in the current thread. */

有關如何將 C-API 用於具有每個直譯器 GIL 的子直譯器的更多示例,請參閱 Modules/_xxsubinterpretersmodule.c

(由 Eric Snow 在 gh-104210 等貢獻。)

PEP 669:CPython 的低影響監控

PEP 669 定義了一個新的 API,用於分析器、偵錯程式和其他工具來監控 CPython 中的事件。它涵蓋了廣泛的事件,包括呼叫、返回、行、異常、跳轉等等。這意味著您只為所使用的內容付費,為幾乎零開銷的偵錯程式和覆蓋工具提供了支援。有關詳細資訊,請參閱 sys.monitoring

(由 Mark Shannon 在 gh-103082 中貢獻。)

PEP 688:在 Python 中訪問緩衝區協議

PEP 688 引入了一種從 Python 程式碼中使用緩衝區協議的方法。實現了 __buffer__() 方法的類現在可以用作緩衝區型別。

新的 collections.abc.Buffer 抽象基類提供了一種表示緩衝區物件的標準方式,例如在型別註釋中。新的 inspect.BufferFlags 列舉表示可用於自定義緩衝區建立的標誌。(由 Jelle Zijlstra 在 gh-102500 中貢獻。)

PEP 709:推導式內聯

字典、列表和集合推導式現在是內聯的,而不是為每次執行推導式建立一個新的單用途函式物件。這使得推導式的執行速度提高了兩倍。有關更多詳細資訊,請參閱PEP 709

推導式迭代變數保持隔離,不會覆蓋外部範圍中同名變數,也不會在推導式之後可見。內聯確實導致了一些可見的行為更改

  • 回溯中不再有單獨的推導式幀,並且跟蹤/剖析不再將推導式顯示為函式呼叫。

  • symtable 模組將不再為每個推導式生成子符號表;相反,推導式的區域性變數將包含在父函式的符號表中。

  • 在推導式內部呼叫 locals() 現在包含推導式外部的變數,並且不再包含推導式“引數”的合成 .0 變數。

  • 在跟蹤下執行(例如程式碼覆蓋率測量)時,直接迭代 locals() 的推導式(例如 [k for k in locals()])可能會看到“RuntimeError: dictionary changed size during iteration”。這與在例如 for k in locals(): 中已看到行為相同。為避免錯誤,首先建立一個要迭代的鍵列表:keys = list(locals()); [k for k in keys]

(由 Carl Meyer 和 Vladimir Matveev 在PEP 709 中貢獻。)

改進的錯誤訊息

  • NameError 異常提升到頂層時,直譯器顯示的錯誤訊息現在可能會建議標準庫中的模組。(由 Pablo Galindo 在 gh-98254 中貢獻。)

    >>> sys.version_info
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'sys' is not defined. Did you forget to import 'sys'?
    
  • 改進例項的 NameError 異常的錯誤建議。現在,如果在方法中引發 NameError 並且例項具有與異常中名稱完全相同的屬性,則建議將包含 self.<NAME>,而不是方法作用域中最接近的匹配項。(由 Pablo Galindo 在 gh-99139 中貢獻。)

    >>> class A:
    ...    def __init__(self):
    ...        self.blech = 1
    ...
    ...    def foo(self):
    ...        somethin = blech
    ...
    >>> A().foo()
    Traceback (most recent call last):
      File "<stdin>", line 1
        somethin = blech
                   ^^^^^
    NameError: name 'blech' is not defined. Did you mean: 'self.blech'?
    
  • 改進當用戶輸入 import x from y 而不是 from y import xSyntaxError 錯誤訊息。(由 Pablo Galindo 在 gh-98931 中貢獻。)

    >>> import a.y.z from b.y.z
    Traceback (most recent call last):
      File "<stdin>", line 1
        import a.y.z from b.y.z
        ^^^^^^^^^^^^^^^^^^^^^^^
    SyntaxError: Did you mean to use 'from ... import ...' instead?
    
  • 從失敗的 from <module> import <name> 語句引發的 ImportError 異常現在包含基於 <module> 中可用名稱的 <name> 值建議。(由 Pablo Galindo 在 gh-91058 中貢獻。)

    >>> from collections import chainmap
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ImportError: cannot import name 'chainmap' from 'collections'. Did you mean: 'ChainMap'?
    

其他語言更改

  • 解析器在解析包含空位元組的原始碼時現在會引發 SyntaxError。(由 Pablo Galindo 在 gh-96670 中貢獻。)

  • 反斜槓字元對不是有效的轉義序列時,現在會生成 SyntaxWarning,而不是 DeprecationWarning。例如,re.compile("\d+\.\d+") 現在會發出 SyntaxWarning"\d" 是一個無效的轉義序列,對正則表示式使用原始字串:re.compile(r"\d+\.\d+"))。在未來的 Python 版本中,最終將引發 SyntaxError,而不是 SyntaxWarning。(由 Victor Stinner 在 gh-98401 中貢獻。)

  • 在 Python 3.11 中已棄用的大於 0o377 的八進位制轉義(例如:"\477"),現在會生成 SyntaxWarning,而不是 DeprecationWarning。在未來的 Python 版本中,它們最終將成為 SyntaxError。(由 Victor Stinner 在 gh-98401 中貢獻。)

  • 在推導式目標部分中使用的、未儲存到變數現在可以在賦值表示式 (:=) 中使用。例如,在 [(b := 1) for a, b.prop in some_iter] 中,現在允許對 b 進行賦值。請注意,根據PEP 572,仍然不允許對推導式目標部分中儲存到變數(例如 a)進行賦值。(由 Nikita Sobolev 在 gh-100581 中貢獻。)

  • 在類或型別的 __set_name__ 方法中引發的異常不再被 RuntimeError 包裝。上下文資訊作為PEP 678 註釋新增到異常中。(由 Irit Katriel 在 gh-77757 中貢獻。)

  • try-except* 結構處理整個 ExceptionGroup 並引發另一個異常時,該異常不再包裝在 ExceptionGroup 中。3.11.4 版本也已更改。(由 Irit Katriel 在 gh-103590 中貢獻。)

  • 垃圾回收器現在僅在 Python 位元組碼評估迴圈的評估斷路器機制上執行,而不是物件分配。GC 也可以在呼叫 PyErr_CheckSignals() 時執行,因此需要長時間執行而無需執行任何 Python 程式碼的 C 擴充套件也有機會定期執行 GC。(由 Pablo Galindo 在 gh-97922 中貢獻。)

  • 所有預期布林引數的內建和擴充套件可呼叫物件現在接受任何型別的引數,而不僅僅是 boolint。(由 Serhiy Storchaka 在 gh-60203 中貢獻。)

  • memoryview 現在支援半浮點型別(“e”格式程式碼)。(由 Donghee Na 和 Antoine Pitrou 在 gh-90751 中貢獻。)

  • slice 物件現在是可雜湊的,允許它們用作字典鍵和集合項。(由 Will Bradshaw、Furkan Onder 和 Raymond Hettinger 在 gh-101264 中貢獻。)

  • sum() 現在使用 Neumaier 求和法來提高浮點數或混合整數和浮點數求和時的精度和可交換性。(由 Raymond Hettinger 在 gh-100425 中貢獻。)

  • ast.parse() 在解析包含空位元組的原始碼時現在引發 SyntaxError 而不是 ValueError。(由 Pablo Galindo 在 gh-96670 中貢獻。)

  • tarfile 中的提取方法和 shutil.unpack_archive() 具有新的 filter 引數,允許限制可能令人驚訝或危險的 tar 功能,例如在目標目錄外部建立檔案。有關詳細資訊,請參閱tarfile 提取過濾器。在 Python 3.14 中,預設值將切換為 'data'。(由 Petr Viktorin 在PEP 706 中貢獻。)

  • 如果底層對映是可雜湊的,則 types.MappingProxyType 例項現在是可雜湊的。(由 Serhiy Storchaka 在 gh-87995 中貢獻。)

  • 透過新的環境變數 PYTHONPERFSUPPORT 和命令列選項 -X perf,以及新的 sys.activate_stack_trampoline()sys.deactivate_stack_trampoline()sys.is_stack_trampoline_active() 函式,增加了對 perf 分析器的支援。(由 Pablo Galindo 設計。由 Pablo Galindo 和 Christian Heimes 貢獻,並得到 Gregory P. Smith [Google] 和 Mark Shannon 在 gh-96123 中的貢獻。)

新模組

  • 無。

改進的模組

array

asyncio

  • asyncio 中寫入套接字的效能顯著提高。asyncio 現在在寫入套接字時避免不必要的複製,如果平臺支援,則使用 sendmsg()。(由 Kumar Aditya 在 gh-91166 中貢獻。)

  • 新增 asyncio.eager_task_factory()asyncio.create_eager_task_factory() 函式,以允許事件迴圈選擇啟用渴望任務執行,從而使某些用例速度提高 2 到 5 倍。(由 Jacob Bower & Itamar Oren 在 gh-102853gh-104140gh-104138 中貢獻)

  • 在 Linux 上,如果 os.pidfd_open() 可用且功能正常,asyncio 預設使用 asyncio.PidfdChildWatcher,而不是 asyncio.ThreadedChildWatcher。(由 Kumar Aditya 在 gh-98024 中貢獻。)

  • 事件迴圈現在為每個平臺使用最佳可用的子觀察者(如果支援則為 asyncio.PidfdChildWatcher,否則為 asyncio.ThreadedChildWatcher),因此不建議手動配置子觀察者。(由 Kumar Aditya 在 gh-94597 中貢獻。)

  • asyncio.run() 新增 loop_factory 引數,允許指定自定義事件迴圈工廠。(由 Kumar Aditya 在 gh-99388 中貢獻。)

  • 新增 asyncio.current_task() 的 C 實現,速度提高了 4-6 倍。(由 Itamar Oren 和 Pranav Thulasiram Bhat 在 gh-100344 中貢獻。)

  • asyncio.iscoroutine() 現在對生成器返回 False,因為 asyncio 不支援舊的基於生成器的協程。(由 Kumar Aditya 在 gh-102748 中貢獻。)

  • asyncio.wait()asyncio.as_completed() 現在接受生成任務的生成器。(由 Kumar Aditya 在 gh-78530 中貢獻。)

calendar

csv

dis

  • 偽指令操作碼(編譯器使用但不會出現在可執行位元組碼中)現在在 dis 模組中公開。HAVE_ARGUMENT 仍然與真實操作碼相關,但對偽指令無用。請改用新的 dis.hasarg 集合。(由 Irit Katriel 在 gh-94216 中貢獻。)

  • 新增 dis.hasexc 集合以表示設定異常處理程式的指令。(由 Irit Katriel 在 gh-94216 中貢獻。)

fractions

importlib.resources

inspect

itertools

  • 新增 itertools.batched(),用於收集等長元組,其中最後一批可能比其餘的短。(由 Raymond Hettinger 在 gh-98363 中貢獻。)

math

  • 新增 math.sumprod() 以計算乘積之和。(由 Raymond Hettinger 在 gh-100485 中貢獻。)

  • 擴充套件 math.nextafter() 以包含 steps 引數,用於一次向上或向下移動多個步長。(由 Matthias Goergens、Mark Dickinson 和 Raymond Hettinger 在 gh-94906 中貢獻。)

os

  • 新增 os.PIDFD_NONBLOCK 以在非阻塞模式下使用 os.pidfd_open() 為程序開啟檔案描述符。(由 Kumar Aditya 在 gh-93312 中貢獻。)

  • os.DirEntry 現在包含一個 os.DirEntry.is_junction() 方法來檢查條目是否為連線點。(由 Charles Machalow 在 gh-99547 中貢獻。)

  • 在 Windows 上新增 os.listdrives()os.listvolumes()os.listmounts() 函式,用於列舉驅動器、卷和掛載點。(由 Steve Dower 在 gh-102519 中貢獻。)

  • os.stat()os.lstat() 在 Windows 上現在更準確。st_birthtime 欄位現在將填充檔案的建立時間,並且 st_ctime 已棄用但仍包含建立時間(但在未來將返回最後一次元資料更改,以便與其他平臺保持一致)。st_dev 最多可以是 64 位,st_ino 最多可以是 128 位,具體取決於您的檔案系統,並且 st_rdev 始終設定為零而不是不正確的值。這兩個函式在 Windows 的新版本上可能顯著更快。(由 Steve Dower 在 gh-99726 中貢獻。)

os.path

pathlib

platform

  • 增加對檢測 Windows 11 和 Windows Server 2012 以後版本的支援。此前,在 Windows Server 2012 以後和 Windows 11 上的查詢會返回 Windows-10。(由 Steve Dower 在 gh-89545 中貢獻。)

pdb

  • 新增方便變數以在除錯會話中臨時儲存值,並提供對當前幀或返回值等值的快速訪問。(由 Tian Gao 在 gh-103693 中貢獻。)

random

shutil

  • shutil.make_archive() 現在將 root_dir 引數傳遞給支援它的自定義歸檔器。在這種情況下,它不再暫時更改程序的當前工作目錄到 root_dir 來執行歸檔。(由 Serhiy Storchaka 在 gh-74696 中貢獻。)

  • shutil.rmtree() 現在接受一個新的引數 onexc,它是一個錯誤處理程式,類似於 onerror,但它期望一個異常例項而不是 (typ, val, tb) 三元組。onerror 已棄用。(由 Irit Katriel 在 gh-102828 中貢獻。)

  • shutil.which() 現在會查閱 PATHEXT 環境變數,即使給定的 cmd 包含目錄元件,也會在 Windows 上的 PATH 中查詢匹配項。(由 Charles Machalow 在 gh-103179 中貢獻。)

    shutil.which() 在查詢 Windows 上的可執行檔案時將呼叫 NeedCurrentDirectoryForExePathW,以確定當前工作目錄是否應新增到搜尋路徑中。(由 Charles Machalow 在 gh-103179 中貢獻。)

    shutil.which() 將返回與 cmd 匹配的路徑,該路徑在 Windows 上的搜尋路徑中,PATHEXT 中的元件優先於其他地方的直接匹配。(由 Charles Machalow 在 gh-103179 中貢獻。)

sqlite3

statistics

  • 擴充套件 statistics.correlation() 以包含 ranked 方法,用於計算等級資料的 Spearman 相關性。(由 Raymond Hettinger 在 gh-95861 中貢獻。)

sys

tempfile

threading

tkinter

  • tkinter.Canvas.coords() 現在會展平其引數。它現在不僅接受獨立的座標(x1, y1, x2, y2, ...)和座標序列([x1, y1, x2, y2, ...]),還接受成對分組的座標((x1, y1), (x2, y2), ...[(x1, y1), (x2, y2), ...]),就像 create_*() 方法一樣。(由 Serhiy Storchaka 在 gh-94473 貢獻)。

tokenize

types

typing

  • isinstance()runtime-checkable protocols 的檢查現在使用 inspect.getattr_static() 而不是 hasattr() 來查詢屬性是否存在。這意味著描述符和 __getattr__() 方法在對可執行時檢查協議進行 isinstance() 檢查時不再意外求值。然而,這也可能意味著一些過去被認為是可執行時檢查協議例項的物件,在 Python 3.12+ 中可能不再被認為是該協議的例項,反之亦然。大多數使用者不太可能受到此更改的影響。(由 Alex Waygood 在 gh-102433 貢獻)。

  • 可執行時檢查協議的成員現在在類建立後立即被視為“凍結”。修補可執行時檢查協議上的屬性仍然有效,但對比較物件與協議的 isinstance() 檢查沒有影響。例如:

    >>> from typing import Protocol, runtime_checkable
    >>> @runtime_checkable
    ... class HasX(Protocol):
    ...     x = 1
    ...
    >>> class Foo: ...
    ...
    >>> f = Foo()
    >>> isinstance(f, HasX)
    False
    >>> f.x = 1
    >>> isinstance(f, HasX)
    True
    >>> HasX.y = 2
    >>> isinstance(f, HasX)  # unchanged, even though HasX now also has a "y" attribute
    True
    

    此更改是為了加快對可執行時檢查協議的 isinstance() 檢查。

  • runtime-checkable protocolsisinstance() 檢查的效能配置檔案已顯著改變。大多數對只有少數成員的協議的 isinstance() 檢查應該比 3.11 快至少 2 倍,有些可能快 20 倍或更多。然而,對具有許多成員的協議的 isinstance() 檢查可能比 Python 3.11 慢。(由 Alex Waygood 在 gh-74690gh-103193 貢獻)。

  • 所有 typing.TypedDicttyping.NamedTuple 類現在都具有 __orig_bases__ 屬性。(由 Adrian Garcia Badaracco 在 gh-103699 貢獻)。

  • typing.dataclass_transform() 添加了 frozen_default 引數。(由 Erik De Bonte 在 gh-99957 貢獻)。

unicodedata

  • Unicode 資料庫已更新至版本 15.0.0。(由 Benjamin Peterson 在 gh-96734 貢獻)。

unittest

添加了 --durations 命令列選項,顯示 N 個最慢的測試用例。

python3 -m unittest --durations=3 lib.tests.test_threading
.....
Slowest test durations
----------------------------------------------------------------------
1.210s     test_timeout (Lib.test.test_threading.BarrierTests)
1.003s     test_default_timeout (Lib.test.test_threading.BarrierTests)
0.518s     test_timeout (Lib.test.test_threading.EventTests)

(0.000 durations hidden.  Use -v to show these durations.)
----------------------------------------------------------------------
Ran 158 tests in 9.869s

OK (skipped=3)

(由 Giampaolo Rodola 在 gh-48330 貢獻)

uuid

最佳化

  • 從 Unicode 物件中移除了 wstrwstr_length 成員。這在 64 位平臺上減少了 8 或 16 位元組的物件大小。( PEP 623) (由 Inada Naoki 在 gh-92536 貢獻)。

  • 添加了在構建過程中使用 BOLT 二進位制最佳化器的實驗性支援,這可將效能提高 1-5%。(由 Kevin Modzelewski 在 gh-90536 貢獻,由 Donghee Na 在 gh-101525 調優)

  • 對於包含組引用的替換字串,正則表示式替換(函式 re.sub()re.subn() 以及相應的 re.Pattern 方法)的速度提高了 2-3 倍。(由 Serhiy Storchaka 在 gh-91524 貢獻)。

  • 透過延遲昂貴的字串格式化,加快了 asyncio.Task 的建立。(由 Itamar Oren 在 gh-103793 貢獻)。

  • 作為 tokenize 模組中覆蓋 PEP 701 所需更改的副作用,tokenize.tokenize()tokenize.generate_tokens() 函式的速度提高了 64%。(由 Marta Gómez Macías 和 Pablo Galindo 在 gh-102856 貢獻)。

  • 透過新的 LOAD_SUPER_ATTR 指令,加快了 super() 方法呼叫和屬性載入。(由 Carl Meyer 和 Vladimir Matveev 在 gh-103497 貢獻)。

CPython 位元組碼變更

演示和工具

  • 移除了包含舊演示指令碼的 Tools/demo/ 目錄。可以在 old-demos 專案 中找到副本。(由 Victor Stinner 在 gh-97681 貢獻)。

  • 移除了 Tools/scripts/ 目錄中過時的示例指令碼。可以在 old-demos 專案 中找到副本。(由 Victor Stinner 在 gh-97669 貢獻)。

已棄用

計劃在 Python 3.13 中移除

模組(請參閱 PEP 594

  • aifc

  • audioop

  • cgi

  • cgitb

  • chunk

  • crypt

  • imghdr

  • mailcap

  • msilib

  • nis

  • nntplib

  • ossaudiodev

  • pipes

  • sndhdr

  • spwd

  • sunau

  • telnetlib

  • uu

  • xdrlib

其他模組

API

計劃在 Python 3.14 中移除

  • argparseargparse.BooleanOptionalActiontypechoicesmetavar 引數已棄用,並將在 3.14 中移除。(由 Nikita Sobolev 在 gh-92248 貢獻)。

  • ast:以下功能自 Python 3.8 起已在文件中棄用,現在在執行時訪問或使用時會發出 DeprecationWarning,並將在 Python 3.14 中移除:

    • ast.Num

    • ast.Str

    • ast.Bytes

    • ast.NameConstant

    • ast.Ellipsis

    請改用 ast.Constant。(由 Serhiy Storchaka 在 gh-90953 貢獻)。

  • asyncio:

    • 子程序觀察器類 asyncio.MultiLoopChildWatcherasyncio.FastChildWatcherasyncio.AbstractChildWatcherasyncio.SafeChildWatcher 已棄用,並將在 Python 3.14 中移除。(由 Kumar Aditya 在 gh-94597 貢獻)。

    • asyncio.set_child_watcher()asyncio.get_child_watcher()asyncio.AbstractEventLoopPolicy.set_child_watcher()asyncio.AbstractEventLoopPolicy.get_child_watcher() 已棄用,並將在 Python 3.14 中移除。(由 Kumar Aditya 在 gh-94597 貢獻)。

    • 如果未設定當前事件迴圈,並且預設事件迴圈策略的 get_event_loop() 方法決定建立一個事件迴圈,它現在會發出 DeprecationWarning。(由 Serhiy Storchaka 和 Guido van Rossum 在 gh-100160 貢獻)。

  • emailemail.utils.localtime() 中的 isdst 引數已棄用。(由 Alan Williams 在 gh-72346 貢獻)。

  • importlib.abc 棄用類

    • importlib.abc.ResourceReader

    • importlib.abc.Traversable

    • importlib.abc.TraversableResources

    請改用 importlib.resources.abc 類:

    (由 Jason R. Coombs 和 Hugo van Kemenade 在 gh-93963 中貢獻。)

  • itertools 對複製、深複製和 pickle 操作的支援未文件化、效率低下、歷史上存在 bug 且不一致。這將從 3.14 中移除,以顯著減少程式碼量和維護負擔。(由 Raymond Hettinger 在 gh-101588 貢獻)。

  • multiprocessing:在 Linux、BSD 和其他非 macOS POSIX 平臺上(目前預設為 'fork'),預設啟動方法將更改為更安全的方法 (gh-84559)。新增執行時警告被認為過於具有破壞性,因為大多數程式碼預計不會關心。使用 get_context()set_start_method() API 顯式指定您的程式碼何時 *需要* 'fork'。請參閱 上下文和啟動方法

  • pathlibis_relative_to()relative_to():傳遞額外引數已棄用。

  • pkgutilpkgutil.find_loader()pkgutil.get_loader() 現在會引發 DeprecationWarning;請改用 importlib.util.find_spec()。(由 Nikita Sobolev 在 gh-97850 貢獻)。

  • pty:

  • sqlite3:

  • urlliburllib.parse.Quoter 已棄用:它無意作為公共 API。(由 Gregory P. Smith 在 gh-88168 貢獻)。

計劃在 Python 3.15 中移除

  • 匯入系統

    • 在設定模組的 __cached__ 屬性時,若未同時設定 __spec__.cached,此行為已被棄用。在 Python 3.15 中,匯入系統或標準庫將不再設定或考慮 __cached__ 屬性。(由 gh-97879 貢獻)

    • 在設定模組的 __package__ 屬性時,若未同時設定 __spec__.parent,此行為已被棄用。在 Python 3.15 中,匯入系統或標準庫將不再設定或考慮 __package__ 屬性。(由 gh-97879 貢獻)

  • ctypes:

    • 未寫入文件的 ctypes.SetPointerType() 函式自 Python 3.13 起已被棄用。

  • http.server:

    • 過時且很少使用的 CGIHTTPRequestHandler 已從 Python 3.13 開始棄用。沒有直接的替代品。任何將 Web 伺服器與請求處理程式對接的方式都比 CGI 好。

    • python -m http.server 命令列介面的 --cgi 旗標已自 Python 3.13 起棄用。

  • importlib:

    • load_module() 方法:請改用 exec_module()

  • locale:

  • pathlib:

  • platform:

    • java_ver() 已自 Python 3.13 起棄用。此函式僅對 Jython 支援有用,其 API 令人困惑,且基本未經測試。

  • sysconfig:

  • threading:

    • RLock() 在 Python 3.15 中將不再接受任何引數。自 Python 3.14 起,傳遞任何引數的行為已被棄用,因為 Python 版本不允許任何引數,但 C 版本允許任意數量的位置或關鍵字引數,並會忽略所有引數。

  • types:

  • typing:

    • 用於建立 NamedTuple 類的未寫入文件的關鍵字引數語法(例如,Point = NamedTuple("Point", x=int, y=int))已自 Python 3.13 起棄用。請改用基於類的語法或函式式語法。

    • 使用 TypedDict 的函式式語法時,未向 fields 引數傳遞值(TD = TypedDict("TD"))或傳遞 NoneTD = TypedDict("TD", None))自 Python 3.13 起已棄用。請使用 class TD(TypedDict): passTD = TypedDict("TD", {}) 來建立具有零欄位的 TypedDict。

    • typing.no_type_check_decorator() 裝飾器函式已自 Python 3.13 起棄用。在 typing 模組中存在八年後,它仍未被任何主流型別檢查器支援。

  • wave:

  • zipimport:

計劃在 Python 3.16 中移除

計劃在 Python 3.17 中移除

  • collections.abc:

    • collections.abc.ByteString 計劃在 Python 3.17 中移除。

      要測試 obj 是否在執行時實現了緩衝區協議,請使用 isinstance(obj, collections.abc.Buffer)。在型別註解中,請使用 Buffer 或顯式指定程式碼支援的型別的聯合型別(例如 bytes | bytearray | memoryview)。

      ByteString 最初旨在作為 bytesbytearray 的超型別。然而,由於 ABC 從未有任何方法,知道一個物件是 ByteString 的例項實際上並不能告訴你任何關於該物件的有用資訊。其他常見的緩衝區型別,如 memoryview,也從未被理解為 ByteString 的子型別(無論是執行時還是靜態型別檢查器)。

      有關更多詳細資訊,請參閱 PEP 688。(由 Shantanu Jain 在 gh-91896 貢獻)。

  • typing:

    • 在 Python 3.14 之前,舊式聯合型別是透過私有類 typing._UnionGenericAlias 實現的。該類對於實現已不再需要,但為了向後相容而保留,並計劃在 Python 3.17 中移除。使用者應使用文件化的內省輔助工具,如 typing.get_origin()typing.get_args(),而不是依賴於私有實現細節。

    • typing.ByteString,自 Python 3.9 起已棄用,計劃在 Python 3.17 中移除。

      要測試 obj 是否在執行時實現了緩衝區協議,請使用 isinstance(obj, collections.abc.Buffer)。在型別註解中,請使用 Buffer 或顯式指定程式碼支援的型別的聯合型別(例如 bytes | bytearray | memoryview)。

      ByteString 最初旨在作為 bytesbytearray 的超型別。然而,由於 ABC 從未有任何方法,知道一個物件是 ByteString 的例項實際上並不能告訴你任何關於該物件的有用資訊。其他常見的緩衝區型別,如 memoryview,也從未被理解為 ByteString 的子型別(無論是執行時還是靜態型別檢查器)。

      有關更多詳細資訊,請參閱 PEP 688。(由 Shantanu Jain 在 gh-91896 貢獻)。

計劃在未來版本中移除

以下 API 將在未來移除,但目前尚未確定移除日期。

  • argparse:

    • 巢狀引數組和巢狀互斥組的做法已被棄用。

    • add_argument_group() 傳遞未寫入文件的關鍵字引數 prefix_chars 的做法現已棄用。

    • argparse.FileType 型別轉換器已被棄用。

  • builtins:

    • 生成器:throw(type, exc, tb)athrow(type, exc, tb) 簽名已被棄用:請改用單引數簽名的 throw(exc)athrow(exc)

    • 目前 Python 接受緊跟著關鍵字的數字字面量,例如 0in x1or x0if 1else 2。這允許混淆和模糊的表示式,例如 [0x1for x in y](可以解釋為 [0x1 for x in y][0x1f or x in y])。如果數字字面量緊跟著關鍵字 andelseforifinisor 之一,則會引發語法警告。在未來版本中,這將更改為語法錯誤。( gh-87999 )

    • __index__()__int__() 方法返回非 int 型別的支援:這些方法將被要求返回 int 的嚴格子類的例項。

    • __float__() 方法返回 float 的嚴格子類的支援:這些方法將被要求返回 float 的例項。

    • __complex__() 方法返回 complex 的嚴格子類的支援:這些方法將被要求返回 complex 的例項。

    • int() 委託給 __trunc__() 方法的做法。

    • complex() 建構函式中將複數作為 realimag 引數傳遞的做法現已棄用;它應該僅作為單個位置引數傳遞。(由 Serhiy Storchaka 在 gh-109218 中貢獻。)

  • calendarcalendar.Januarycalendar.February 常量已棄用,並由 calendar.JANUARYcalendar.FEBRUARY 替換。(由 Prince Roshan 在 gh-103636 貢獻)。

  • codecs:請使用 open() 而不是 codecs.open()。(gh-133038

  • codeobject.co_lnotab:請改用 codeobject.co_lines() 方法。

  • datetime:

    • utcnow():請使用 datetime.datetime.now(tz=datetime.UTC)

    • utcfromtimestamp():請使用 datetime.datetime.fromtimestamp(timestamp, tz=datetime.UTC)

  • gettext:複數值必須是整數。

  • importlib:

  • importlib.metadata:

    • EntryPoints 元組介面。

    • 返回值的隱式 None

  • loggingwarn() 方法已自 Python 3.3 起棄用,請改用 warning()

  • mailbox:使用 StringIO 輸入和文字模式已被棄用,請改用 BytesIO 和二進位制模式。

  • os:在多執行緒程序中呼叫 os.register_at_fork()

  • pydoc.ErrorDuringImportexc_info 引數使用元組值的做法已被棄用,請改用異常例項。

  • re:現在對正則表示式中的數字組引用和組名應用了更嚴格的規則。現在只接受 ASCII 數字序列作為數字引用。位元組串模式和替換字串中的組名現在只能包含 ASCII 字母、數字和下劃線。(由 Serhiy Storchaka 在 gh-91760 中貢獻。)

  • sre_compilesre_constantssre_parse 模組。

  • shutilrmtree()onerror 引數在 Python 3.12 中已棄用;請改用 onexc 引數。

  • ssl 選項和協議

    • 不帶協議引數的 ssl.SSLContext 已被棄用。

    • ssl.SSLContext: set_npn_protocols()selected_npn_protocol() 已被棄用:請改用 ALPN。

    • ssl.OP_NO_SSL* 選項

    • ssl.OP_NO_TLS* 選項

    • ssl.PROTOCOL_SSLv3

    • ssl.PROTOCOL_TLS

    • ssl.PROTOCOL_TLSv1

    • ssl.PROTOCOL_TLSv1_1

    • ssl.PROTOCOL_TLSv1_2

    • ssl.TLSVersion.SSLv3

    • ssl.TLSVersion.TLSv1

    • ssl.TLSVersion.TLSv1_1

  • threading 方法

  • typing.Text (gh-92332)。

  • 內部類 typing._UnionGenericAlias 不再用於實現 typing.Union。為了保持與使用此私有類的使用者的相容性,將提供一個相容性墊片,至少持續到 Python 3.17。(由 Jelle Zijlstra 在 gh-105499 中貢獻。)

  • unittest.IsolatedAsyncioTestCase:從測試用例返回非 None 的值已被棄用。

  • urllib.parse 中已棄用的函式:請改用 urlparse()

    • splitattr()

    • splithost()

    • splitnport()

    • splitpasswd()

    • splitport()

    • splitquery()

    • splittag()

    • splittype()

    • splituser()

    • splitvalue()

    • to_bytes()

  • wsgirefSimpleHandler.stdout.write() 不應進行部分寫入。

  • xml.etree.ElementTree:測試 Element 的真值的做法已被棄用。在未來的版本中,它將始終返回 True。請優先使用顯式的 len(elem)elem is not None 測試。

  • sys._clear_type_cache() 已被棄用:請改用 sys._clear_internal_caches()

已移除

asynchat 和 asyncore

  • 這兩個模組已根據 PEP 594 中的計劃移除,它們自 Python 3.6 起已被棄用。請改用 asyncio。(由 Nikita Sobolev 在 gh-96580 貢獻)。

configparser

distutils

  • 移除了 distutils 包。它在 Python 3.10 中透過 PEP 632 “棄用 distutils 模組”而被棄用。對於仍然使用 distutils 且無法更新到其他專案的專案,可以安裝 setuptools 專案:它仍然提供 distutils。(由 Victor Stinner 在 gh-92584 貢獻)。

ensurepip

  • ensurepip 中移除了捆綁的 setuptools wheel,並停止在 venv 建立的環境中安裝 setuptools。

    pip (>= 22.1) 不需要環境安裝 setuptools。setuptools-based (和 distutils-based) 包仍然可以透過 pip install 使用,因為 pip 將在用於構建包的構建環境中提供 setuptools

    easy_installpkg_resourcessetuptoolsdistutils 不再由 venv 建立或透過 ensurepip 引導的環境中預設提供,因為它們是 setuptools 包的一部分。對於在執行時依賴這些的專案,應將 setuptools 專案宣告為依賴項並單獨安裝(通常使用 pip)。

    (由 Pradyun Gedam 在 gh-95299 貢獻)。

enum

  • 移除了 enumEnumMeta.__getattr__,它不再是列舉屬性訪問所必需的。(由 Ethan Furman 在 gh-95083 貢獻)。

ftplib

  • 移除了 ftplibFTP_TLS.ssl_version 類屬性:請改用 context 引數。(由 Victor Stinner 在 gh-94172 貢獻)。

gzip

  • 移除了 gzipgzip.GzipFilefilename 屬性,該屬性自 Python 2.6 起已棄用,請改用 name 屬性。在寫入模式下,如果 filename 屬性不存在 '.gz' 副檔名,它會新增該副檔名。(由 Victor Stinner 在 gh-94196 貢獻)。

hashlib

  • 移除了 hashlibhashlib.pbkdf2_hmac() 的純 Python 實現,該實現已在 Python 3.10 中棄用。Python 3.10 及更高版本要求 OpenSSL 1.1.1 (PEP 644):此 OpenSSL 版本提供了 pbkdf2_hmac() 的 C 實現,速度更快。(由 Victor Stinner 在 gh-94199 貢獻)。

importlib

  • importlib 中許多先前棄用的清理工作現已完成:

    • module_repr() 的引用和支援已移除。(由 Barry Warsaw 在 gh-97850 貢獻)。

    • importlib.util.set_packageimportlib.util.set_loaderimportlib.util.module_for_loader 都已移除。(由 Brett Cannon 和 Nikita Sobolev 在 gh-65961gh-97850 貢獻)。

    • find_loader()find_module() API 的支援已移除。(由 Barry Warsaw 在 gh-98040 貢獻)。

    • importlib.abc.Finderpkgutil.ImpImporterpkgutil.ImpLoader 已移除。(由 Barry Warsaw 在 gh-98040 貢獻)。

imp

  • imp 模組已移除。(由 Barry Warsaw 在 gh-98040 貢獻)。

    要遷移,請參考以下對應表:

    imp

    importlib

    imp.NullImporter

    None 插入 sys.path_importer_cache

    imp.cache_from_source()

    importlib.util.cache_from_source()

    imp.find_module()

    importlib.util.find_spec()

    imp.get_magic()

    importlib.util.MAGIC_NUMBER

    imp.get_suffixes()

    importlib.machinery.SOURCE_SUFFIXESimportlib.machinery.EXTENSION_SUFFIXESimportlib.machinery.BYTECODE_SUFFIXES

    imp.get_tag()

    sys.implementation.cache_tag

    imp.load_module()

    importlib.import_module()

    imp.new_module(name)

    types.ModuleType(name)

    imp.reload()

    importlib.reload()

    imp.source_from_cache()

    importlib.util.source_from_cache()

    imp.load_source()

    請參閱下文

    imp.load_source() 替換為

    import importlib.util
    import importlib.machinery
    
    def load_source(modname, filename):
        loader = importlib.machinery.SourceFileLoader(modname, filename)
        spec = importlib.util.spec_from_file_location(modname, filename, loader=loader)
        module = importlib.util.module_from_spec(spec)
        # The module is always executed and not cached in sys.modules.
        # Uncomment the following line to cache the module.
        # sys.modules[module.__name__] = module
        loader.exec_module(module)
        return module
    
  • 移除了沒有替代品的 imp 函式和屬性:

    • 未文件化的函式:

      • imp.init_builtin()

      • imp.load_compiled()

      • imp.load_dynamic()

      • imp.load_package()

    • imp.lock_held()imp.acquire_lock()imp.release_lock():鎖定方案已在 Python 3.3 中更改為按模組鎖定。

    • imp.find_module() 常量:SEARCH_ERRORPY_SOURCEPY_COMPILEDC_EXTENSIONPY_RESOURCEPKG_DIRECTORYC_BUILTINPY_FROZENPY_CODERESOURCEIMP_HOOK

io

  • 移除 ioio.OpenWrapper_pyio.OpenWrapper,它們在 Python 3.10 中已棄用:現在只需使用 open()open() (io.open()) 函式是一個內建函式。自 Python 3.10 起,_pyio.open() 也是一個靜態方法。(由 Victor Stinner 在 gh-94169 中貢獻。)

locale

smtpd

  • 根據 PEP 594 中的計劃,smtpd 模組已被移除,它在 Python 3.4.7 和 3.5.4 中已棄用。請改用 aiosmtpd PyPI 模組或任何其他基於 asyncio 的伺服器。(由 Oleg Iarygin 在 gh-93243 中貢獻。)

sqlite3

  • 以下未文件化的 sqlite3 功能,在 Python 3.10 中已棄用,現已移除

    • sqlite3.enable_shared_cache()

    • sqlite3.OptimizedUnicode

    如果必須使用共享快取,請在 URI 模式下使用 cache=shared 查詢引數開啟資料庫。

    sqlite3.OptimizedUnicode 文字工廠自 Python 3.3 起已成為 str 的別名。以前將文字工廠設定為 OptimizedUnicode 的程式碼現在可以顯式使用 str,或依賴於預設值(也是 str)。

    (由 Erlend E. Aasland 在 gh-92548 中貢獻。)

ssl

  • 移除 sslssl.RAND_pseudo_bytes() 函式,它在 Python 3.6 中已棄用:請改用 os.urandom()ssl.RAND_bytes()。(由 Victor Stinner 在 gh-94199 中貢獻。)

  • 移除 ssl.match_hostname() 函式。它在 Python 3.7 中已棄用。OpenSSL 自 Python 3.7 起執行主機名匹配,Python 不再使用 ssl.match_hostname() 函式。(由 Victor Stinner 在 gh-94199 中貢獻。)

  • 移除 ssl.wrap_socket() 函式,它在 Python 3.7 中已棄用:請改為建立 ssl.SSLContext 物件並呼叫其 ssl.SSLContext.wrap_socket 方法。任何仍使用 ssl.wrap_socket() 的包都是損壞且不安全的。該函式既不傳送 SNI TLS 擴充套件也不驗證伺服器主機名。程式碼受 CWE 295(不當證書驗證)的影響。(由 Victor Stinner 在 gh-94199 中貢獻。)

unittest

webbrowser

  • webbrowser 移除對過時瀏覽器的支援。移除的瀏覽器包括:Grail、Mosaic、Netscape、Galeon、Skipstone、Iceape、Firebird 以及 Firefox 35 及以下版本(gh-102871)。

xml.etree.ElementTree

  • 移除純 Python 實現的 ElementTree.Element.copy() 方法,它在 Python 3.10 中已棄用,請改用 copy.copy() 函式。xml.etree.ElementTree 的 C 實現沒有 copy() 方法,只有 __copy__() 方法。(由 Victor Stinner 在 gh-94383 中貢獻。)

zipimport

  • 移除 zipimportfind_loader()find_module() 方法,它們在 Python 3.10 中已棄用:請改用 find_spec() 方法。請參閱 PEP 451 以瞭解原理。(由 Victor Stinner 在 gh-94379 中貢獻。)

其他

  • 移除文件 MakefileDoc/tools/rstlint.py 中的 suspicious 規則,兩者都支援 sphinx-lint。(由 Julien Palard 在 gh-98179 中貢獻。)

  • ftplibimaplibpoplibsmtplib 模組中移除 keyfilecertfile 引數,並從 http.client 模組中移除 key_filecert_filecheck_hostname 引數,所有這些都在 Python 3.6 中已棄用。請改用 context 引數(在 imaplib 中為 ssl_context)。(由 Victor Stinner 在 gh-94172 中貢獻。)

  • 移除幾個標準庫模組和測試中 Jython 相容性補丁。(由 Nikita Sobolev 在 gh-99482 中貢獻。)

  • ctypes 模組中移除 _use_broken_old_ctypes_structure_semantics_ 標誌。(由 Nikita Sobolev 在 gh-99285 中貢獻。)

移植到 Python 3.12

本節列出了前面描述過的變更以及其他可能需要修改程式碼的 bug 修復。

Python API 的變化

  • 現在對正則表示式中的數字組引用和組名稱應用更嚴格的規則。現在只接受 ASCII 數字序列作為數字引用。位元組模式和替換字串中的組名稱現在只能包含 ASCII 字母和數字以及下劃線。(由 Serhiy Storchaka 在 gh-91760 中貢獻。)

  • 移除自 Python 3.10 起已棄用的 randrange() 功能。以前,randrange(10.0) 無損地轉換為 randrange(10)。現在,它會引發 TypeError。此外,對非整數值(如 randrange(10.5)randrange('10'))引發的異常已從 ValueError 更改為 TypeError。這還可以防止 randrange(1e25) 會靜默地從比 randrange(10**25) 更大的範圍中選擇的錯誤。(最初由 Serhiy Storchaka 建議 gh-86388。)

  • argparse.ArgumentParser 更改了從檔案讀取引數(例如 fromfile_prefix_chars 選項)的編碼和錯誤處理程式,從預設文字編碼(例如 locale.getpreferredencoding(False))更改為 檔案系統編碼和錯誤處理程式。Windows 上的引數檔案應以 UTF-8 而不是 ANSI 內碼表進行編碼。

  • 移除在 Python 3.4.7 和 3.5.4 中已棄用的基於 asyncoresmtpd 模組。推薦的替代方案是基於 asyncioaiosmtpd PyPI 模組。

  • shlex.split():為 s 引數傳遞 None 現在會引發異常,而不是讀取 sys.stdin。此功能在 Python 3.9 中已棄用。(由 Victor Stinner 在 gh-94352 中貢獻。)

  • os 模組不再接受類位元組路徑,例如 bytearraymemoryview 型別:只接受確切的 bytes 型別作為位元組字串。(由 Victor Stinner 在 gh-98393 中貢獻。)

  • syslog.openlog()syslog.closelog() 如果在子直譯器中使用,現在會失敗。syslog.syslog() 仍可在子直譯器中使用,但現在只有在主直譯器中已呼叫 syslog.openlog() 的情況下才行。這些新限制不適用於主直譯器,因此只有非常小一部分使用者可能會受到影響。此更改有助於直譯器隔離。此外,syslog 是一個圍繞程序全域性資源的包裝器,最好由主直譯器管理。(由 Donghee Na 在 gh-99127 中貢獻。)

  • 移除 cached_property() 的未文件化鎖定行為,因為它鎖定了類的所有例項,導致高鎖爭用。這意味著如果兩個執行緒競爭,快取屬性 getter 函式現在可以為單個例項執行多次。對於大多數簡單的快取屬性(例如那些冪等且僅根據例項的其他屬性計算值的屬性),這會很好。如果需要同步,請在快取屬性 getter 函式內或多執行緒訪問點周圍實現鎖定。

  • sys._current_exceptions() 現在返回從執行緒 ID 到異常例項的對映,而不是到 (typ, exc, tb) 元組的對映。(由 Irit Katriel 在 gh-103176 中貢獻。)

  • 使用 tarfileshutil.unpack_archive() 提取 tar 檔案時,傳遞 filter 引數以限制可能令人意外或危險的功能。有關詳細資訊,請參閱 提取過濾器

  • 由於 PEP 701 引入的更改,tokenize.tokenize()tokenize.generate_tokens() 函式的輸出現在已更改。這意味著 f-字串不再發出 STRING 令牌,而是生成 PEP 701 中描述的令牌:FSTRING_STARTFSTRING_MIDDLEFSTRING_END 現在除了表示式元件中分詞的適當令牌外,還為 f-字串“字串”部分發出。例如,對於 f-字串 f"start {1+1} end",舊版分詞器發出

    1,0-1,18:           STRING         'f"start {1+1} end"'
    

    而新版本發出

    1,0-1,2:            FSTRING_START  'f"'
    1,2-1,8:            FSTRING_MIDDLE 'start '
    1,8-1,9:            OP             '{'
    1,9-1,10:           NUMBER         '1'
    1,10-1,11:          OP             '+'
    1,11-1,12:          NUMBER         '1'
    1,12-1,13:          OP             '}'
    1,13-1,17:          FSTRING_MIDDLE ' end'
    1,17-1,18:          FSTRING_END    '"'
    

    此外,由於支援 PEP 701 所需的更改,可能還會出現一些細微的行為更改。其中一些更改包括

    • 分詞一些無效 Python 字元(如 !)時發出的令牌的 type 屬性已從 ERRORTOKEN 更改為 OP

    • 不完整的單行字串現在也像不完整的多行字串一樣引發 tokenize.TokenError

    • 一些不完整或無效的 Python 程式碼現在在分詞時會引發 tokenize.TokenError,而不是返回任意 ERRORTOKEN 令牌。

    • 同一檔案中混合使用製表符和空格作為縮排不再受支援,並且會引發 TabError

  • threading 模組現在期望 _thread 模組具有 _is_main_interpreter 屬性。它是一個不帶引數的函式,如果當前直譯器是主直譯器,則返回 True

    任何提供自定義 _thread 模組的庫或應用程式都應提供 _is_main_interpreter()。(請參閱 gh-112826。)

構建變更

  • Python 不再使用 setup.py 來構建共享 C 擴充套件模組。configure 指令碼中檢測標頭檔案和庫等構建引數。擴充套件由 Makefile 構建。大多數擴充套件使用 pkg-config 並回退到手動檢測。(由 Christian Heimes 在 gh-93939 中貢獻。)

  • 現在需要使用帶有兩個引數的 va_start()(例如 va_start(args, format),)來構建 Python。va_start() 不再使用單個引數呼叫。(由 Kumar Aditya 在 gh-93207 中貢獻。)

  • 如果 Clang 編譯器接受該標誌,CPython 現在使用 ThinLTO 選項作為預設連結時間最佳化策略。(由 Donghee Na 在 gh-89536 中貢獻。)

  • Makefile 中新增 COMPILEALL_OPTS 變數,以在 make install 中覆蓋 compileall 選項(預設值:-j0)。還將 3 個 compileall 命令合併為一個命令,以同時構建所有最佳化級別(0、1、2)的 .pyc 檔案。(由 Victor Stinner 在 gh-99289 中貢獻。)

  • 為 64 位 LoongArch 新增平臺三元組

    • loongarch64-linux-gnusf

    • loongarch64-linux-gnuf32

    • loongarch64-linux-gnu

    (由 Zhang Na 在 gh-90656 中貢獻。)

  • PYTHON_FOR_REGEN 現在需要 Python 3.10 或更高版本。

  • 現在需要 Autoconf 2.71 和 aclocal 1.16.4 才能重新生成 configure。(由 Christian Heimes 在 gh-89886 中貢獻。)

  • python.org 的 Windows 版本和 macOS 安裝程式現在使用 OpenSSL 3.0。

C API 變更

新功能

  • PEP 683:引入 不朽物件,允許物件繞過引用計數,以及 C-API 的相關更改

    • _Py_IMMORTAL_REFCNT:定義物件為不朽的引用計數。

      作為不朽的。

    • _Py_IsImmortal 檢查物件是否具有不朽引用計數。

    • PyObject_HEAD_INIT 當與 Py_BUILD_CORE 一起使用時,這現在會將引用計數初始化為

      _Py_IMMORTAL_REFCNT

    • SSTATE_INTERNED_IMMORTAL 已intern unicode 物件的識別符號

      是不朽的。

    • SSTATE_INTERNED_IMMORTAL_STATIC 已intern unicode 物件的識別符號

      是不朽且靜態的

    • sys.getunicodeinternedsize 這返回已intern的 unicode 物件的總數

      已intern。現在需要它才能使 refleak.py 正確跟蹤引用計數和分配的塊

    (由 Eddie Elizondo 在 gh-84436 中貢獻。)

  • PEP 684:新增新的 Py_NewInterpreterFromConfig() 函式和 PyInterpreterConfig,它們可用於建立具有自己 GIL 的子直譯器。(有關詳細資訊,請參閱 PEP 684:每個直譯器一個 GIL。)(由 Eric Snow 在 gh-104110 中貢獻。)

  • 在有限 C API 版本 3.12 中,Py_INCREF()Py_DECREF() 函式現在作為不透明函式呼叫實現,以隱藏實現細節。(由 Victor Stinner 在 gh-105387 中貢獻。)

移植到 Python 3.12

  • 基於 Py_UNICODE* 表示的舊版 Unicode API 已被移除。請遷移到基於 UTF-8 或 wchar_t* 的 API。

  • 引數解析函式(如 PyArg_ParseTuple())不再支援基於 Py_UNICODE* 的格式(例如 uZ)。請遷移到其他 Unicode 格式,如 szesU

  • 所有靜態內建型別的 tp_weaklist 始終為 NULL。這是 PyTypeObject 上的一個內部欄位,但我們指出此更改以防有人直接訪問該欄位。為避免損壞,請考慮改用現有的公共 C-API,或者,如果需要,使用(僅限內部)_PyObject_GET_WEAKREFS_LISTPTR() 宏。

  • 此僅限內部的 PyTypeObject.tp_subclasses 現在可能不是有效的物件指標。其型別已更改為 void* 以反映這一點。我們提到這一點以防有人直接訪問內部欄位。

    要獲取子類列表,請呼叫 Python 方法 __subclasses__()(例如,使用 PyObject_CallMethod())。

  • PyUnicode_FromFormat()PyUnicode_FromFormatV() 中添加了對更多格式選項(左對齊、八進位制、大寫十六進位制、intmax_tptrdiff_twchar_t C 字串、可變寬度和精度)的支援。(由 Serhiy Storchaka 在 gh-98836 中貢獻。)

  • PyUnicode_FromFormat()PyUnicode_FromFormatV() 中的無法識別的格式字元現在會設定 SystemError。在以前的版本中,它會導致格式字串的其餘部分按原樣複製到結果字串中,並丟棄任何額外的引數。(由 Serhiy Storchaka 在 gh-95781 中貢獻。)

  • 修復 PyUnicode_FromFormat()PyUnicode_FromFormatV() 中錯誤的符號位置。(由 Philip Georgi 在 gh-95504 中貢獻。)

  • 希望新增 __dict__ 或弱引用槽的擴充套件類應使用 Py_TPFLAGS_MANAGED_DICTPy_TPFLAGS_MANAGED_WEAKREF,而不是 tp_dictoffsettp_weaklistoffset。仍支援使用 tp_dictoffsettp_weaklistoffset,但它不完全支援多重繼承(gh-95589),並且效能可能更差。宣告 Py_TPFLAGS_MANAGED_DICT 的類必須呼叫 _PyObject_VisitManagedDict()_PyObject_ClearManagedDict() 來遍歷和清除其例項的字典。要清除弱引用,請像以前一樣呼叫 PyObject_ClearWeakRefs()

  • PyUnicode_FSDecoder() 函式不再接受類位元組路徑,例如 bytearraymemoryview 型別:只接受確切的 bytes 型別作為位元組字串。(由 Victor Stinner 在 gh-98393 中貢獻。)

  • Py_CLEARPy_SETREFPy_XSETREF 宏現在只評估其引數一次。如果引數具有副作用,這些副作用將不再重複。(由 Victor Stinner 在 gh-98724 中貢獻。)

  • 直譯器的錯誤指示器現在始終規範化。這意味著 PyErr_SetObject()PyErr_SetString() 和其他設定錯誤指示器的函式現在在儲存異常之前對其進行規範化。(由 Mark Shannon 在 gh-101578 中貢獻。)

  • _Py_RefTotal 不再是權威的,僅為了 ABI 相容性而保留。請注意,它是一個內部全域性變數,僅在除錯版本中可用。如果您碰巧正在使用它,那麼您需要開始使用 _Py_GetGlobalRefTotal()

  • 以下函式現在為新建立的型別選擇適當的元類

    建立其元類重寫 tp_new 的類已棄用,並且在 Python 3.14+ 中將被禁止。請注意,這些函式忽略元類的 tp_new,可能導致不完全初始化。

    請注意,PyType_FromMetaclass()(在 Python 3.12 中新增)已經禁止建立其元類重寫 tp_new(Python 中的 __new__())的類。

    由於 tp_new 重寫了 PyType_From* 函式幾乎所有功能,因此兩者彼此不相容。現有行為——在型別建立的幾個步驟中忽略元類——通常是不安全的,因為(元)類假定已呼叫 tp_new。沒有簡單的通用解決方法。以下之一可能適合您

    • 如果您控制元類,請避免在其中使用 tp_new

      • 如果可以跳過初始化,則可以在 tp_init 中完成。

      • 如果元類不需要從 Python 例項化,請使用 Py_TPFLAGS_DISALLOW_INSTANTIATION 標誌將其 tp_new 設定為 NULL。這使得 PyType_From* 函式可以接受它。

    • 避免使用 PyType_From* 函式:如果您不需要 C 特有的功能(槽或設定例項大小),請透過 呼叫 元類來建立型別。

    • 如果您 知道 可以安全跳過 tp_new,請使用 Python 中的 warnings.catch_warnings() 過濾掉棄用警告。

  • PyOS_InputHookPyOS_ReadlineFunctionPointer 不再在 子直譯器 中呼叫。這是因為客戶端通常依賴於程序範圍的全域性狀態(因為這些回撥無法恢復擴充套件模組狀態)。

    這還避免了擴充套件程式可能發現自己執行在不支援(或尚未載入)的子直譯器中的情況。有關詳細資訊,請參閱 gh-104668

  • PyLongObject 的內部結構已更改以提高效能。儘管 PyLongObject 的內部結構是私有的,但它們被一些擴充套件模組使用。內部欄位不應再直接訪問,而應改用以 PyLong_... 開頭的 API 函式。提供了兩個新的 不穩定 API 函式,用於高效訪問適合單個機器字的 PyLongObject 的值

  • 現在要求透過 PyMem_SetAllocator() 設定的自定義分配器是執行緒安全的,無論記憶體域如何。沒有自己狀態的分配器,包括“鉤子”,不受影響。如果您的自定義分配器尚未執行緒安全並且您需要指導,請建立新的 GitHub issue 並抄送 @ericsnowcurrently

已棄用

預計在 Python 3.14 中移除

預計在 Python 3.15 中移除

預計在 Python 3.16 中移除

  • 捆綁的 libmpdec 副本。

預計在未來版本中移除

以下 API 已被棄用並將被移除,但目前尚未確定移除日期。

已移除

  • 移除 token.h 標頭檔案。從未有過公共的詞法分析器 C API。token.h 標頭檔案僅用於 Python 內部使用。(由 Victor Stinner 在 gh-92651 中貢獻。)

  • 舊版 Unicode API 已移除。詳情請參閱 PEP 623

    • PyUnicode_WCHAR_KIND

    • PyUnicode_AS_UNICODE()

    • PyUnicode_AsUnicode()

    • PyUnicode_AsUnicodeAndSize()

    • PyUnicode_AS_DATA()

    • PyUnicode_FromUnicode()

    • PyUnicode_GET_SIZE()

    • PyUnicode_GetSize()

    • PyUnicode_GET_DATA_SIZE()

  • 移除 PyUnicode_InternImmortal() 函式宏。(由 Victor Stinner 在 gh-85858 中貢獻。)