Python 3.12 有什麼新功能

編輯者:

Adam Turner

本文介紹了 Python 3.12 與 3.11 相比多了哪些新功能。Python 3.12 於 2023 年 10 月 2 日發布。完整詳情請見 changelog

也參考

PEP 693 -- Python 3.12 發布時程

發布重點摘要

Python 3.12 是 Python 程式語言的穩定版本,包含了語言和標準函式庫的綜合變更。標準函式庫的變更主要集中在清理棄用的 API、可用性和正確性。值得注意的是,distutils 套件已從標準函式庫中移除。ospathlib 中的檔案系統支援進行了許多改進,並且有數個模組得到更好的效能。

語言變更主要集中在可用性,因為 f-字串已經移除了許多限制,並且持續改進 'Did you mean ...' 建議。新的型別參數語法type 陳述式改進了泛型型別型別別名在與靜態型別檢查器一起使用上的效率。

這篇文章並不試圖提供所有新功能的完整規格,而是提供一個方便的概覽。完整詳情應參考文件,如標準函式庫參考語言參考。如果你想了解某個新功能的完整實作和設計理念,請參考該功能的 PEP;但請注意 PEP 通常在功能完全實作後就不再更新。


新增語法特性:

新增語法特性:

直譯器改進:

Python 資料模型改進:

標準函式庫中的顯著改進:

安全性改進:

  • 將於 hashlib 中 SHA1、SHA3、SHA2-384、SHA2-512 和 MD5 內建實作替換為來自 HACL* 專案的經正式驗證的程式碼。這些內建實作仍然作為備援方案 (fallback),僅在 OpenSSL 不提供它們時使用。

C API 改進:

  • PEP 697,不穩定 C API 層

  • PEP 683,不滅物件 (immortal objects)

CPython 實作改進:

  • PEP 709,行內綜合運算 (comprehension inlining)

  • 對 Linux perf 分析器的 CPython 支援

  • 在支援的平台上實作堆疊溢位保護

新增型別特性:

重要的棄用、刪除或限制:

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

  • PEP 632:刪除 distutils 套件。請參閱遷移指南以查看替換原有 API 的建議。如果你在 Python 3.12 及後續版本中仍然需要它們,第三方套件 Setuptools 會繼續提供 distutils

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

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

新增功能

PEP 695:型別參數語法

PEP 484 下的泛型類別和函式是使用較冗長語法來宣告,這使得型別參數的作用域不明確,並且需要顯式地宣告變異數 (variance)。

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 引入了一種使用型別陳述式來宣告型別別名的新方法,該方法會建立一個 TypeAliasType 的實例:

type Point = tuple[float, float]

型別別名也可以是泛型

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

新的語法允許宣告 TypeVarTupleParamSpec 參數,以及帶有邊界 (bounds) 或限制 (constraints) 的 TypeVar 參數:

type IntFunc[**P] = Callable[P, int]  # ParamSpec
type LabeledTuple[*Ts] = tuple[str, *Ts]  # TypeVarTuple
type HashableSequence[T: Hashable] = Sequence[T]  # 帶有邊界的 TypeVar
type IntOrStrSequence[T: (int, str)] = Sequence[T]  # 帶有限制的 TypeVar

透過此語法建立之型別別名的值和型別變數的邊界和限制,僅會根據需求來求值(請參閱延遲求值 (lazy evaluation))。這意味著型別別名可以參照在檔案中後續定義的其他型別。

透過型別參數串列宣告的型別參數在宣告作用域及任何巢狀作用域內皆為可見,但在外部作用域內不可見。例如,它們可以用在泛型類別方法的型別註釋中或類別主體中。但是,在定義類別後,它們不能在模組作用域內使用。有關型別參數的 runtime 語義的詳細描述,請參閱 Type parameter lists

為了支援這些作用域語義而引入了一種新的作用域,即註釋作用域 (annotation scope)。註釋作用域的行為在很大程度上類似於函式作用域,但與封閉類別作用域的交互方式不同。在 Python 3.13 中,註釋也將在註釋作用域內進行求值。

詳情請見 PEP 695

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

PEP 701:f 字串的語法形式化

PEP 701 解除了 f 字串在使用上的一些限制。f 字串內的運算式元件現在可以是任何有效的 Python 運算式,包括重複使用與包含 f 字串相同的引號的字串、多行運算式、註解、反斜線和 unicode 轉義序列。讓我們詳細介紹一下這些內容:

  • 引號重用:在 Python 3.11 中,重複使用與封閉的 f 字串相同的引號會引發 SyntaxError,強制使用者使用其他可用的引號(例如,如果 f 字串使用單引號,則使用雙引號或三引號)。在 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 字串沒有明確的限制,但事實上字串引號不能在 f 字串的運算式元件內重複使用,因此無法任意嵌套 f 字串。事實上,這是嵌套層數最多的 f 字串:

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

    由於現在 f 字串可以在運算式元件內包含任何有效的 Python 運算式,因此現在可以任意嵌套 f 字串:

    >>> f"{f"{f"{f"{f"{f"{1+1}"}"}"}"}"}"
    '2'
    
  • 多行運算式和註解:在 Python 3.11 中,f 字串運算式必須在單行中定義,即使 f 字串中的運算式通常可以跨越多行(就像在多行上定義的 list 常值一樣),從而使它們更難閱讀。在 Python 3.12 中,你現在可以定義跨越多行的 f 字串,並新增內嵌註解:

    >>> 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 字串運算式不能包含任何 \ 字元。這也影響了 unicode 轉義序列(例如 \N{snowman}),因為它們包含 \N 部分,該部分以前不能是 f 字串運算式元件的一部分。現在,你可以像這樣定義運算式:

    >>> 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 字串),現在 f 字串的錯誤訊息更加精確,並且包含錯誤的確切位置。例如,在 Python 3.11 中,以下 f 字串會引發 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 中,由於使用 PEG 剖析器剖析 f 字串,因此錯誤訊息可以更精確並顯示整行:

>>> 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 使用,不過 Python API 預計在 3.13 中提供

使用新的 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;
}
/* 新的直譯器現在會在目前執行緒中啟用。 */

關於如何使用子直譯器的 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 ABC 提供了一種表示緩衝區物件的標準方法,例如在型別註釋中。新的 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 x 時出現的 SyntaxError 錯誤訊息。(由 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 中貢獻。)

  • 值大於 0o377 的八進位轉義符(例如:"\477")在 Python 3.11 中已棄用,現在會生成 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 位元組碼評估迴圈的 eval 斷路器機制上運行,而不是在物件分配上運行。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 中貢獻。)

  • tarfileshutil.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() 函式,新增對效能分析器的支援。(由 Pablo Galindo 設計。由 Pablo Galindo 和 Christian Heimes 貢獻,Gregory P. Smith [Google] 和 Mark Shannon 在 gh-96123 中也有貢獻。)

新增模組

  • 無。

改進的模組

array

asyncio

  • asyncio 中寫入 socket 的效能得到了顯著提高。asyncio 現在可以避免在寫入 socket 時進行不必要的複製,並在平台支援的情況下使用 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 中貢獻。)

  • 事件迴圈現在會為每個平台使用最佳的子行程監看器 (child watcher)(如果支援則使用 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() 函式,用於列舉磁碟機 (drives)、磁碟區 (volumes) 和掛載點 (mount points)。(由 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 和 2012 之後的 Windows Server 版本的偵測支援。之前,在比 Windows Server 2012 更新的 Windows Server 平台和 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 環境變數來查找 Windows 上 PATH 內的匹配項,即使給定的 cmd 包含目錄元件也是如此。(由 Charles Machalow 在 gh-103179 中貢獻。)

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

    shutil.which() 將優先回傳 cmdPATHEXT 中元件相匹配的路徑,然後才在 Windows 搜尋路徑中的其他位置進行直接匹配。(由 Charles Machalow 在 gh-103179 中貢獻。)

sqlite3

statistics

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 檢查的協定的檢查,現在使用 inspect.getattr_static() 而不是 hasattr() 來查找屬性是否存在。這意味著在針對 可在 runtime 檢查的協定的 isinstance() 檢查期間,描述器和 __getattr__() 方法不再意外地被求值。然而,這也可能意味著一些曾經被視為 可在 runtime 檢查的協定實例的物件在 Python 3.12+ 上可能不再被視為該協定的實例,反之亦然。大多數使用者不太可能受到此更改的影響。(由 Alex Waygood 在 gh-102433 中貢獻。)

  • 現在,一旦建立了類別,可在 runtime 檢查的協定的成員就會在 runtime 被視為「凍結」。將屬性 monkey-patch 到 可在 runtime 檢查的協定上仍然有效,但不會影響將物件與協定進行比較的 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)  # 沒有改變,即便 HasX 現在有 "y" 屬性
    True
    

    進行此更改是為了加快針對 可在 runtime 檢查的協定的 isinstance() 檢查。

  • isinstance() 針對可在 runtime 檢查的協定進行檢查的效能概況已發生顯著變化。大多數 isinstance() 針對只有少數成員的協定的檢查應該比 3.11 中至少快 2 倍,有些可能快 20 倍或更多。然而,isinstance() 對具有許多成員的協定進行檢查可能比 Python 3.11 慢。(由 Alex Waygood 在 gh-74690gh-103193 中貢獻。)

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

  • 新增 frozen_default 參數至 typing.dataclass_transform()。(由 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 起,下列功能已在文件中被棄用,現在在存取或使用時會於 runtime 發出 DeprecationWarning,並將在 Python 3.14 中移除:

    • ast.Num

    • ast.Str

    • ast.Bytes

    • ast.NameConstant

    • ast.Ellipsis

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

  • asyncio

    • 已棄用並將在 Python 3.14 中移除的 child watcher 類別:asyncio.MultiLoopChildWatcherasyncio.FastChildWatcherasyncio.AbstractChildWatcherasyncio.SafeChildWatcher。(由 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 貢獻。)

  • email:已棄用 email.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 有不以文件記錄、效率低下、過去常有 bug 且不一致的 copy、deepcopy 和 pickle 操作支援。將在 3.14 中移除以大幅減少程式碼量和維護負擔。(由 Raymond Hettinger 於 gh-101588 貢獻。)

  • multiprocessing:預設的啟動方法將在 Linux、BSD 和其他非 macOS POSIX 平台上更改為更安全的方法,目前 'fork' 是預設值 (gh-84559)。對此增加一個 runtime 警告被認為太過擾人,因為 大多數程式碼不會在意。請使用 get_context()set_start_method() API 來明確指定你的程式碼何時需要 'fork'。請參閱 Contexts and start methods

  • pathlib:已棄用 is_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 中待移除的項目

  • 引入系統 (import system):

    • 在模組上設定 __cached__ 而沒有設定 __spec__.cached 的做法已被棄用。在 Python 3.15 中,引入系統或標準函式庫將不再設定或考慮 __cached__。(gh-97879)

    • 在模組上設定 __package__ 而沒有設定 __spec__.parent 的做法已被棄用。在 Python 3.15 中,引入系統或標準函式庫將不再設定或考慮 __package__。(gh-97879)

  • ctypes

    • 自 Python 3.13 起,未記錄的 ctypes.SetPointerType() 函式已被棄用。

  • http.server

    • 過時且很少使用的 CGIHTTPRequestHandler 自 Python 3.13 起已被棄用。不存在直接的替代。任何東西都比 CGI 更好地將 Web 伺服器與請求處理程序介接起來。

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

  • importlib

    • load_module() method:請改用 exec_module()

  • locale

  • pathlib

  • platform

    • 自 Python 3.13 起,java_ver() 已被棄用。此函式僅對 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 棄用。請改用基於類別的語法或函式語法 (functional syntax)。

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

    • 自 Python 3.13 起,typing.no_type_check_decorator() 裝飾器函式已被棄用。在 typing 模組中使用了八年之後,它尚未得到任何主要型別檢查器的支援。

  • wave

  • zipimport

Python 3.16 中待移除的項目

Python 3.17 中待移除的項目

  • collections.abc

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

      使用 isinstance(obj, collections.abc.Buffer) 來測試 obj 是否在 runtime 實作了緩衝區協定。在型別註解的使用中,請用 Buffer 或明確指定你的程式碼所支援型別的聯集(例如 bytes | bytearray | memoryview)。

      ByteString 最初被設計為一個抽象類別,以作為 bytesbytearray 的超型別 (supertype)。然而由於 ABC 從未擁有任何方法,知道一個物件是 ByteString 的實例從未真正告訴你任何關於該物件的有用資訊。其他常見的緩衝區型別如 memoryview 也從未被理解為 ByteString 的子型別(無論是在 runtime 還是由靜態型別檢查器)。

      更多細節請見 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 中移除。

      使用 isinstance(obj, collections.abc.Buffer) 來測試 obj 是否在 runtime 實作了緩衝區協定。在型別註解的使用中,請用 Buffer 或明確指定你的程式碼所支援型別的聯集(例如 bytes | bytearray | memoryview)。

      ByteString 最初被設計為一個抽象類別,以作為 bytesbytearray 的超型別 (supertype)。然而由於 ABC 從未擁有任何方法,知道一個物件是 ByteString 的實例從未真正告訴你任何關於該物件的有用資訊。其他常見的緩衝區型別如 memoryview 也從未被理解為 ByteString 的子型別(無論是在 runtime 還是由靜態型別檢查器)。

      更多細節請見 PEP 688。(由 Shantanu Jain 於 gh-91896 貢獻。)

未來版本中的待移除項目

以下 API 將在未來被移除,雖然目前尚未安排移除日期。

  • argparse

    • 巢狀引數群組和巢狀互斥群組已被棄用。

    • 將未以文件記錄的關鍵字引數 prefix_chars 傳遞給 add_argument_group() 的做法現在已被棄用。

    • 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 的實例。

    • 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

  • logging:自 Python 3.3 起,warn() 方法已被棄用,請改用 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.SSLContextset_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 都將提供一個相容性 shim。(由 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(以及基於 distutils)的套件仍然可以透過 pip install 來使用,因為 pip 會在其用於建置套件的建置環境中提供 setuptools

    venv 建立或以 ensurepip 啟動引導的環境中不再預設提供 easy_installpkg_resourcessetuptoolsdistutils,因為它們是 setuptools 套件的一部分。對於在 runtime 依賴這些工具的專案,應將 setuptools 專案宣告為相依套件並單獨安裝(通常使用 pip)。

    (由 Pradyun Gedam 於 gh-95299 中貢獻。)

enum

  • 移除 enumEnumMeta.__getattr__,對於列舉屬性的存取不再會需要它。

ftplib

  • 移除 ftplibFTP_TLS.ssl_version 類別屬性:請改用 context 參數。(由 Victor Stinner 於 gh-94172 中貢獻。)

gzip

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

hashlib

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)
        # 此模組都會被執行且不會被快取於 sys.modules。
        # 要快取模組的話可以把下面一行取消註解
        # 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():鎖定 scheme 在 Python 3.3 中已改為模組鎖 (per-module locks)。

    • 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 中已被棄用。請改用 PyPI 上的 aiosmtpd 模組或任何其他基於 asyncio 的伺服器。

sqlite3

  • 以下未以文件記錄的 sqlite3 功能已在 Python 3.10 中被棄用、現在已被移除:

    • sqlite3.enable_shared_cache()

    • sqlite3.OptimizedUnicode

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

    自 Python 3.3 起,sqlite3.OptimizedUnicode 文字工廠一直是 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 起已被棄用。自 Python 3.7 起,OpenSSL 會執行主機名稱比對,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

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

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 編碼,而不是 Windows 的 ANSI Codepage。

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

  • shlex.split():以 None 做為 s 引數傳遞現在會引發例外,而不是讀取 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() 鎖定行為已被刪除,因為它鎖定了類別的所有實例,從而導致高鎖定爭用 (high lock contention)。這意味著,如果兩個執行緒競爭,快取的屬性 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 字串 "string" 部分發出。例如,對於 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,而不是在 tokenize 時回傳任意 ERRORTOKEN 標記。

    • 不再支援在同一檔案中混合 Tab 字元和空格作為縮排,並且會引發 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 中貢獻。)

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

  • CPython 現在會使用 ThinLTO 選項作為預設連結時間最佳化策略(如果 Clang 編譯器接受該旗標)。(由 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_IMMORTAL_REFCNT(與 Py_BUILD_CORE 一起使用時)。

    • SSTATE_INTERNED_IMMORTAL 駐留的 (interned) unicode 物件的識別字

      那是不滅的。

    • SSSTATE_INTERNED_IMMORTAL_STATIC 駐留的 unicode 的識別字

      不滅且靜態的物件

    • sys.getunicodeinternedsize 這會回傳 unicode 的總數

      已駐留的物件。現在 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* 的格式(例如 u, Z)。請遷移到其他 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__ 或弱參照 (weak reference) 插槽的擴充類別應分別使用 Py_TPFLAGS_MANAGED_DICTPy_TPFLAGS_MANAGED_WEAKREF,而非 tp_dictoffsettp_weaklistoffsettp_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 的功能(插槽 (slot) 或設定實例大小),請透過呼叫元類別來建立型別。

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

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

    這也避免了擴充可能發現自己在它們不支援(或尚未載入)的子直譯器中運行的情況。請參閱 gh-104668 了解更多資訊。

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

  • 透過 PyMem_SetAllocator() 設定的自訂分配器現在要求是執行緒安全的,無論記憶體域如何。沒有自己狀態的分配器(包括 "hooks")不受影響。如果你的自訂分配器還不是執行緒安全的並且你需要指導,請建立一個新的 GitHub 問題並抄送 @ericsnowcurrently

已棄用

Python 3.14 中待移除的項目

Python 3.15 中待移除的項目

Python 3.16 中待移除的項目

  • libmpdecimal 的打包副本 (bundled copy)。

未來版本中的待移除項目

下列 API 已被棄用並將會被移除,不過目前尚未訂定移除日期。

已移除

  • 移除 token.h 標頭檔案。從未有任何公開的 tokenizer 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 中貢獻。)