Python 3.11 中的新功能

編輯:

Pablo Galindo Salgado

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

摘要 – 釋出亮點

  • Python 3.11 比 Python 3.10 快 10-60%。平均而言,我們在標準基準測試套件上測得 1.25 倍的加速。有關詳細資訊,請參閱 更快的 CPython

新語法功能

新的內建功能

新的標準庫模組

直譯器的改進

新的型別特性

重要的廢棄、移除和限制

新功能

PEP 657: 追溯中更精細的錯誤位置

現在,在列印追溯時,直譯器將指向導致錯誤的精確表示式,而不僅僅是行。例如

Traceback (most recent call last):
  File "distance.py", line 11, in <module>
    print(manhattan_distance(p1, p2))
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "distance.py", line 6, in manhattan_distance
    return abs(point_1.x - point_2.x) + abs(point_1.y - point_2.y)
                           ^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'x'

以前的直譯器版本只會指向行,使得哪個物件是 None 變得模糊不清。這些增強的錯誤在處理深度巢狀的 dict 物件和多個函式呼叫時也很有幫助

Traceback (most recent call last):
  File "query.py", line 37, in <module>
    magic_arithmetic('foo')
  File "query.py", line 18, in magic_arithmetic
    return add_counts(x) / 25
           ^^^^^^^^^^^^^
  File "query.py", line 24, in add_counts
    return 25 + query_user(user1) + query_user(user2)
                ^^^^^^^^^^^^^^^^^
  File "query.py", line 32, in query_user
    return 1 + query_count(db, response['a']['b']['c']['user'], retry=True)
                               ~~~~~~~~~~~~~~~~~~^^^^^
TypeError: 'NoneType' object is not subscriptable

以及複雜的算術表示式

Traceback (most recent call last):
  File "calculation.py", line 54, in <module>
    result = (x / y / z) * (a / b / c)
              ~~~~~~^~~
ZeroDivisionError: division by zero

此外,增強的追溯功能所使用的資訊可透過通用 API 獲得,該 API 可用於關聯 位元組碼 指令 與原始碼位置。此資訊可以使用以下方法檢索

有關更多詳細資訊,請參閱 PEP 657。(由 Pablo Galindo、Batuhan Taskaya 和 Ammar Askar 在 bpo-43950 中貢獻。)

備註

此功能要求在 程式碼物件 中儲存列位置,這可能會導致直譯器記憶體使用量和編譯後的 Python 檔案磁碟使用量略有增加。為了避免儲存額外資訊並停用列印額外追溯資訊,請使用 -X no_debug_ranges 命令列選項或 PYTHONNODEBUGRANGES 環境變數。

PEP 654: 異常組和 except*

PEP 654 引入了語言功能,使程式能夠同時引發和處理多個不相關的異常。內建型別 ExceptionGroupBaseExceptionGroup 使得可以將異常分組並一起引發,新的 except* 語法將 except 泛化以匹配異常組的子組。

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

(由 Irit Katriel 在 bpo-45292 中貢獻。PEP 由 Irit Katriel、Yury Selivanov 和 Guido van Rossum 編寫。)

PEP 678: 異常可添加註釋

add_note() 方法已新增到 BaseException。它可用於為異常新增在引發異常時不可用的上下文資訊。新增的註釋會出現在預設追溯中。

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

(由 Irit Katriel 在 bpo-45607 中貢獻。PEP 由 Zac Hatfield-Dodds 編寫。)

Windows py.exe 啟動器改進

Python 3.11 中包含的 Python 安裝管理器 副本已顯著更新。它現在支援 PEP 514 中定義的公司/標籤語法,使用 -V:<company>/<tag> 引數,而不是有限的 -<major>.<minor>。這允許啟動 python.org 上託管的 PythonCore 之外的分發。

使用 -V: 選擇器時,可以省略公司或標籤,但會搜尋所有安裝。例如,-V:OtherPython/ 將選擇為 OtherPython 註冊的“最佳”標籤,而 -V:3.11-V:/3.11 將選擇標籤為 3.11 的“最佳”分發。

使用舊的 -<major>-<major>.<minor>-<major>-<bitness>-<major>.<minor>-<bitness> 引數時,所有現有行為都應保留與過去版本相同,並且只會選擇 PythonCore 的發行版。然而,-64 字尾現在意味著“非 32 位”(不一定是 x86-64),因為有多個受支援的 64 位平臺。32 位執行時透過檢查執行時的標籤是否包含 -32 字尾來檢測。自 3.5 以來,所有 Python 版本都在其 32 位構建中包含了此後綴。

其他語言更改

  • 添加了 -P 命令列選項和 PYTHONSAFEPATH 環境變數,它們會停用在執行指令碼時將指令碼目錄自動新增到 sys.path,或者在使用 -c-m 時將當前目錄自動新增到 sys.path。這確保 import 只會查詢標準庫和已安裝的模組,並避免無意或惡意地使用本地(通常是使用者可寫)目錄中的模組來遮蓋模組。(由 Victor Stinner 在 gh-57684 中貢獻。)

  • 格式化規範迷你語言 中添加了一個 "z" 選項,它在舍入到格式精度後將負零強制轉換為正零。有關更多詳細資訊,請參閱 PEP 682。(由 John Belmonte 在 gh-90153 中貢獻。)

  • sys.path 不再接受位元組。在 Python 3.2 和 3.6 之間某個時候,位元組支援中斷了,直到 Python 3.10.0 釋出後才有人注意到。此外,由於 -bsys.path_importer_cachestrbytes 鍵混合時會發生互動,恢復支援會很麻煩。(由 Thomas Grainger 在 gh-91181 中貢獻。)

其他 CPython 實現變更

新模組

改進的模組

asyncio

contextlib

  • 添加了非並行安全的 chdir() 上下文管理器,用於更改當前工作目錄並在退出時恢復。它是 chdir() 的簡單包裝器。(由 Filipe Laíns 在 bpo-25625 中貢獻)

dataclasses

  • 更改欄位預設值可變性檢查,只允許 可雜湊 的預設值,而不是任何不是 dictlistset 例項的物件。(由 Eric V. Smith 在 bpo-44674 中貢獻。)

datetime

enum

  • EnumMeta 重新命名為 EnumTypeEnumMeta 仍保留為別名)。

  • 添加了 StrEnum,其成員可以用作(且必須是)字串。

  • 添加了 ReprEnum,它只修改成員的 __repr__(),同時為 __str__()__format__()(由 str()format()f-string 使用)返回其字面值(而不是名稱)。

  • 更改了 Enum.__format__()format()str.format()f-string 的預設值)以始終產生與 Enum.__str__() 相同的結果:對於繼承自 ReprEnum 的列舉,它將是成員的值;對於所有其他列舉,它將是列舉和成員名稱(例如 Color.RED)。

  • Flag 列舉和 FlagBoundary 列舉添加了新的 boundary 類引數及其選項,以控制如何處理超出範圍的標誌值。

  • 添加了 verify() 列舉裝飾器和 EnumCheck 列舉及其選項,用於根據幾個特定約束檢查列舉類。

  • 添加了 member()nonmember() 裝飾器,以確保被裝飾的物件是/不是列舉成員。

  • 添加了 property() 裝飾器,它像 property() 一樣工作,但用於列舉。使用它而不是 types.DynamicClassAttribute()

  • 添加了 global_enum() 列舉裝飾器,它調整 __repr__()__str__(),以將值顯示為模組的成員,而不是列舉類。例如,re.RegexFlagASCII 成員顯示為 're.ASCII',而不是 'RegexFlag.ASCII'

  • 增強了 Flag 以支援對其成員使用 len()、迭代和 in/not in。例如,現在以下程式碼可以工作:len(AFlag(3)) == 2 and list(AFlag(3)) == (AFlag.ONE, AFlag.TWO)

  • 更改了 EnumFlag,以便在呼叫 __init_subclass__() 之前定義成員;dir() 現在包含來自混合資料型別的方法等。

  • 更改了 Flag,使其只將主要值(2 的冪)視為規範值,而將複合值(3610 等)視為別名;反轉的標誌會強制轉換為其正等效值。

fcntl

  • 在 FreeBSD 上,支援 F_DUP2FDF_DUP2FD_CLOEXEC 標誌,前者等同於 dup2 用法,後者則額外設定了 FD_CLOEXEC 標誌。

fractions

  • 支援 PEP 515 風格的字串初始化 Fraction。(由 Sergey B Kirpichev 在 bpo-44258 中貢獻。)

  • Fraction 現在實現了 __int__ 方法,因此 isinstance(some_fraction, typing.SupportsInt) 檢查可以透過。(由 Mark Dickinson 在 bpo-44547 中貢獻。)

functools

  • functools.singledispatch() 現在支援將 types.UnionTypetyping.Union 作為排程引數的註解。

    >>> from functools import singledispatch
    >>> @singledispatch
    ... def fun(arg, verbose=False):
    ...     if verbose:
    ...         print("Let me just say,", end=" ")
    ...     print(arg)
    ...
    >>> @fun.register
    ... def _(arg: int | float, verbose=False):
    ...     if verbose:
    ...         print("Strength in numbers, eh?", end=" ")
    ...     print(arg)
    ...
    >>> from typing import Union
    >>> @fun.register
    ... def _(arg: Union[list, set], verbose=False):
    ...     if verbose:
    ...         print("Enumerate this:")
    ...     for i, elem in enumerate(arg):
    ...         print(i, elem)
    ...
    

    (由 Yurii Karabas 在 bpo-46014 中貢獻。)

gzip

  • gzip.compress() 函式與 mtime=0 引數一起使用時,速度更快,因為它將壓縮完全委託給單個 zlib.compress() 操作。此更改有一個副作用:gzip 檔案頭包含一個“OS”位元組。傳統上,gzip 模組總是將其設定為代表“未知”的值 255。現在,當使用 mtime=0 呼叫 compress() 時,它可能會被 Python 連結到的底層 zlib C 庫設定為不同的值。(有關副作用的詳細資訊,請參閱 gh-112346。)

hashlib

  • hashlib.blake2b()hashlib.blake2s() 現在更喜歡 libb2,而不是 Python 內建的副本。(由 Christian Heimes 在 bpo-47095 中貢獻。)

  • SHA3 和 SHAKE 演算法的內部 _sha3 模組現在使用 *tiny_sha3* 而不是 *Keccak Code Package*,以減少程式碼和二進位制大小。hashlib 模組更喜歡 OpenSSL 中最佳化的 SHA3 和 SHAKE 實現。此更改僅影響沒有 OpenSSL 支援的安裝。(由 Christian Heimes 在 bpo-47098 中貢獻。)

  • 添加了 hashlib.file_digest(),一個用於高效雜湊檔案或類檔案物件的輔助函式。(由 Christian Heimes 在 gh-89313 中貢獻。)

IDLE 和 idlelib

  • .pyi 檔案應用語法高亮。(由 Alex Waygood 和 Terry Jan Reedy 在 bpo-45447 中貢獻。)

  • 儲存帶輸入和輸出的 Shell 時包含提示。(由 Terry Jan Reedy 在 gh-95191 中貢獻。)

inspect

locale

logging

math

  • 新增 math.exp2():返回 2 的 x 次冪。(由 Gideon Mitchell 在 bpo-45917 中貢獻。)

  • 新增 math.cbrt():返回 x 的立方根。(由 Ajith Ramachandran 在 bpo-44357 中貢獻。)

  • 為了與 IEEE 754 規範保持一致,更改了兩個 math.pow() 角點情況的行為。操作 math.pow(0.0, -math.inf)math.pow(-0.0, -math.inf) 現在返回 inf。以前它們會引發 ValueError。(由 Mark Dickinson 在 bpo-44339 中貢獻。)

  • math.nan 值現在始終可用。(由 Victor Stinner 在 bpo-46917 中貢獻。)

operator

  • 添加了一個新函式 operator.call,使得 operator.call(obj, *args, **kwargs) == obj(*args, **kwargs)。(由 Antony Lee 在 bpo-44019 中貢獻。)

os

  • 在 Windows 上,os.urandom() 現在使用 BCryptGenRandom(),而不是已廢棄的 CryptGenRandom()。(由 Donghee Na 在 bpo-44611 中貢獻。)

pathlib

re

  • 原子分組 ((?>...)) 和佔有式量詞 (*+, ++, ?+, {m,n}+) 現在在正則表示式中受支援。(由 Jeffrey C. Jacobs 和 Serhiy Storchaka 在 bpo-433030 中貢獻。)

shutil

socket

sqlite3

string

sys

  • sys.exc_info() 現在從 value (異常例項) 派生 typetraceback 欄位,因此當異常在處理過程中被修改時,這些更改會反映在後續呼叫 exc_info() 的結果中。(由 Irit Katriel 在 bpo-45711 中貢獻)。

  • 新增 sys.exception(),它返回活動的異常例項 (等同於 sys.exc_info()[1])。(由 Irit Katriel 在 bpo-46328 中貢獻)。

  • 新增 sys.flags.safe_path 標誌。(由 Victor Stinner 在 gh-57684 中貢獻)。

sysconfig

  • 新增了三個 安裝方案(*posix_venv*、*nt_venv* 和 *venv*),它們在 Python 建立新的虛擬環境或從虛擬環境執行時使用。前兩個方案(*posix_venv* 和 *nt_venv*)是針對非 Windows 和 Windows 的作業系統特定方案,而 *venv* 實際上是根據 Python 執行的作業系統而對其中一個方案的別名。這對於修改 sysconfig.get_preferred_scheme() 的下游分發商非常有用。建立新虛擬環境的第三方程式碼應使用新的 *venv* 安裝方案來確定路徑,就像 venv 所做的那樣。(由 Miro Hrončok 在 bpo-45413 中貢獻)。

tempfile

threading

時間

  • 在 Unix 上,time.sleep() 現在使用 clock_nanosleep()nanosleep() 函式(如果可用),其解析度為 1 納秒(10-9 秒),而不是使用解析度為 1 微秒(10-6 秒)的 select()。(由 Benjamin Szőke 和 Victor Stinner 在 bpo-21302 中貢獻)。

  • 在 Windows 8.1 及更高版本中,time.sleep() 現在使用基於 高解析度計時器 的可等待計時器,其解析度為 100 納秒(10-7 秒)。之前,它的解析度為 1 毫秒(10-3 秒)。(由 Benjamin Szőke、Donghee Na、Eryk Sun 和 Victor Stinner 在 bpo-21302bpo-45429 中貢獻)。

tkinter

  • 添加了方法 info_patchlevel(),它以與 sys.version_info 類似的具名元組形式返回 Tcl 庫的精確版本。(由 Serhiy Storchaka 在 gh-91827 中貢獻)。

traceback

typing

有關主要更改,請參見 與型別提示相關的新特性

  • 新增 typing.assert_never()typing.Nevertyping.assert_never() 對於要求型別檢查器確認一行程式碼不可達很有用。在執行時,它會引發 AssertionError。(由 Jelle Zijlstra 在 gh-90633 中貢獻)。

  • 新增 typing.reveal_type()。這對於要求型別檢查器推斷給定表示式的型別很有用。在執行時,它會列印接收值的型別。(由 Jelle Zijlstra 在 gh-90572 中貢獻)。

  • 新增 typing.assert_type()。這對於要求型別檢查器確認其推斷的給定表示式的型別與給定型別匹配很有用。在執行時,它只是返回接收到的值。(由 Jelle Zijlstra 在 gh-90638 中貢獻)。

  • typing.TypedDict 型別現在可以是泛型的。(由 Samodya Abeysiriwardane 在 gh-89026 中貢獻)。

  • NamedTuple 型別現在可以是泛型的。(由 Serhiy Storchaka 在 bpo-43923 中貢獻)。

  • 允許 typing.Any 的子類化。這對於避免與高度動態類(例如模擬物件)相關的型別檢查器錯誤很有用。(由 Shantanu Jain 在 gh-91154 中貢獻)。

  • typing.final() 裝飾器現在在被裝飾的物件上設定 __final__ 屬性。(由 Jelle Zijlstra 在 gh-90500 中貢獻)。

  • typing.get_overloads() 函式可用於內省函式的過載。typing.clear_overloads() 可用於清除函式的所有已註冊過載。(由 Jelle Zijlstra 在 gh-89263 中貢獻)。

  • Protocol 子類的 __init__() 方法現在得以保留。(由 Adrian Garcia Badarasco 在 gh-88970 中貢獻)。

  • 空元組型別 (Tuple[()]) 的表示被簡化。這會影響內省,例如 get_args(Tuple[()]) 現在求值為 () 而不是 ((),)。(由 Serhiy Storchaka 在 gh-91137 中貢獻)。

  • 透過移除私有 typing._type_check 函式中的可呼叫檢查,放寬了型別註釋的執行時要求。(由 Gregory Beauregard 在 gh-90802 中貢獻)。

  • typing.get_type_hints() 現在支援在 PEP 585 泛型別名 中將字串評估為前向引用。(由 Niklas Rosenstein 在 gh-85542 中貢獻)。

  • typing.get_type_hints() 不再向預設值為 None 的引數新增 Optional。(由 Nikita Sobolev 在 gh-90353 中貢獻)。

  • typing.get_type_hints() 現在支援評估裸字串化 ClassVar 註釋。(由 Gregory Beauregard 在 gh-90711 中貢獻)。

  • typing.no_type_check() 不再修改外部類和函式。它現在也正確地將類方法標記為不進行型別檢查。(由 Nikita Sobolev 在 gh-90729 中貢獻)。

unicodedata

  • Unicode 資料庫已更新至版本 14.0.0。(由 Benjamin Peterson 在 bpo-45190 中貢獻)。

unittest

venv

  • 建立新的 Python 虛擬環境時,會使用 *venv* sysconfig 安裝方案 來確定環境內的路徑。當 Python 在虛擬環境中執行時,相同的安裝方案是預設的。這意味著下游分發商可以在不改變虛擬環境行為的情況下更改預設的 sysconfig 安裝方案。建立新虛擬環境的第三方程式碼也應該這樣做。(由 Miro Hrončok 在 bpo-45413 中貢獻)。

warnings

zipfile

最佳化

本節介紹與 更快的 CPython 專案無關的特定最佳化,該專案在單獨的章節中介紹。

  • 編譯器現在優化了字串字面量中只包含格式程式碼 %s%r%a 的簡單 printf 風格的 % 格式化,使其與相應的 f 字串 表示式一樣快。(由 Serhiy Storchaka 在 bpo-28307 中貢獻)。

  • 整數除法 (//) 更好地針對編譯器最佳化進行了調整。在 x86-64 上,當用小於 2**30 的值除以 int 時,它的速度現在提高了大約 20%。(由 Gregory P. Smith 和 Tim Peters 在 gh-90564 中貢獻)。

  • 對於小於 2**30 的整數,sum() 現在快了近 30%。(由 Stefan Behnel 在 gh-68264 中貢獻)。

  • 列表大小調整在常見情況下得到了最佳化,將 list.append() 的速度提高了約 15%,簡單的 列表推導式 提高了 20-30%。(由 Dennis Sweeney 在 gh-91165 中貢獻)。

  • 當所有鍵都是 Unicode 物件時,字典不再儲存雜湊值,從而減小了 dict 的大小。例如,在 64 位平臺上,sys.getsizeof(dict.fromkeys("abcdefg")) 從 352 位元組減少到 272 位元組(小 23%)。(由 Inada Naoki 在 bpo-46845 中貢獻)。

  • 在使用 asyncio.DatagramProtocol 透過 UDP 傳輸大檔案時,現在速度快了幾個數量級,對於約 60 MiB 的檔案,速度提高了 100 多倍。(由 msoxzw 在 gh-91487 中貢獻)。

  • math 函式 comb()perm() 對於大引數現在快了約 10 倍(對於更大的 *k*,加速更大)。(由 Serhiy Storchaka 在 bpo-37295 中貢獻)。

  • statistics 函式 mean()variance()stdev() 現在以一次性遍歷的方式消耗迭代器,而不是先將其轉換為 list。這使速度提高了一倍,並可以節省大量記憶體。(由 Raymond Hettinger 在 gh-90415 中貢獻)。

  • unicodedata.normalize() 現在以常數時間規範化純 ASCII 字串。(由 Donghee Na 在 bpo-44987 中貢獻)。

更快的 CPython

在 Ubuntu Linux 上使用 GCC 編譯時,CPython 3.11 在 pyperformance 基準測試套件中,平均比 CPython 3.10 快 25%。根據您的工作負載,整體加速可能在 10-60% 之間。

該專案專注於 Python 的兩個主要領域:更快的啟動更快的執行時。不在此專案範圍內的最佳化將在 最佳化 部分單獨列出。

更快的啟動

凍結匯入 / 靜態程式碼物件

Python 將 位元組碼 快取在 __pycache__ 目錄中,以加快模組載入。

以前在 3.10 中,Python 模組執行過程如下

Read __pycache__ -> Unmarshal -> Heap allocated code object -> Evaluate

在 Python 3.11 中,Python 啟動所需的核心模組是“凍結”的。這意味著它們的 程式碼物件(和位元組碼)由直譯器靜態分配。這減少了模組執行過程中的步驟,變為

Statically allocated code object -> Evaluate

Python 3.11 的直譯器啟動速度現在快了 10-15%。這對於使用 Python 的短時執行程式影響很大。

(由 Eric Snow、Guido van Rossum 和 Kumar Aditya 在許多問題中貢獻)。

更快的執行時

更廉價、惰性的 Python 幀

每當 Python 呼叫 Python 函式時,都會建立儲存執行資訊的 Python 幀。以下是新的幀最佳化:

  • 簡化了幀建立過程。

  • 透過在 C 棧上大量重用幀空間來避免記憶體分配。

  • 簡化了內部幀結構,使其只包含基本資訊。幀以前包含額外的除錯和記憶體管理資訊。

舊式的 幀物件 現在只在偵錯程式請求或 Python 內省函式(如 sys._getframe()inspect.currentframe())請求時建立。對於大多數使用者程式碼,根本不建立幀物件。因此,幾乎所有 Python 函式呼叫都顯著加速。我們在 pyperformance 中測量到 3-7% 的加速。(由 Mark Shannon 在 bpo-44590 中貢獻)。

(由 Mark Shannon 在 bpo-44590 中貢獻)。

內聯 Python 函式呼叫

在 Python 函式呼叫期間,Python 將呼叫一個求值 C 函式來解釋該函式的程式碼。這有效地將純 Python 遞迴限制在 C 棧的安全範圍內。

在 3.11 中,當 CPython 檢測到 Python 程式碼呼叫另一個 Python 函式時,它會設定一個新幀,並“跳到”新幀中的新程式碼。這完全避免了呼叫 C 解釋函式。

大多數 Python 函式呼叫現在不消耗 C 棧空間,從而加快了它們的速度。在簡單的遞迴函式(如斐波那契或階乘)中,我們觀察到 1.7 倍的加速。這也意味著遞迴函式可以遞迴更深(如果使用者使用 sys.setrecursionlimit() 增加了遞迴限制)。我們在 pyperformance 中測量到 1-3% 的改進。

(由 Pablo Galindo 和 Mark Shannon 在 bpo-45256 中貢獻)。

PEP 659: 特化自適應直譯器

PEP 659 是 Faster CPython 專案的關鍵部分之一。其基本思想是,儘管 Python 是一種動態語言,但大多數程式碼都有物件和型別很少變化的區域。這個概念被稱為 *型別穩定性*。

在執行時,Python 將嘗試在執行程式碼中尋找常見模式和型別穩定性。然後,Python 將當前操作替換為更專業的特殊操作。這種特殊操作使用只有這些用例/型別才可用的快速路徑,通常比其通用對應項表現更好。這還引入了另一個概念,稱為 *內聯快取*,其中 Python 將昂貴操作的結果直接快取在 位元組碼 中。

特化器還將某些常見的指令對組合成一個超指令,從而減少執行期間的開銷。

Python 只會在看到“熱”程式碼(執行多次)時進行特化。這可以防止 Python 浪費時間在一次性程式碼上。當代碼過於動態或用途發生變化時,Python 也可以取消特化。特化會定期嘗試,並且特化嘗試的成本不高,這使得特化能夠適應新情況。

(PEP 由 Mark Shannon 編寫,靈感來自 Stefan Brunthaler 的想法。有關更多資訊,請參見 PEP 659。由 Mark Shannon 和 Brandt Bucher 實現,Irit Katriel 和 Dennis Sweeney 提供了額外幫助)。

操作

形式

專業化

操作加速 (最高)

貢獻者

二元運算

x + x

x - x

x * x

常用型別(如 intfloatstr)的二元加法、乘法和減法採用其底層型別的自定義快速路徑。

10%

Mark Shannon, Donghee Na, Brandt Bucher, Dennis Sweeney

下標

a[i]

下標容器型別,例如 listtupledict,直接索引底層資料結構。

自定義 __getitem__() 的下標也類似於 內聯 Python 函式呼叫 被內聯。

10-25%

Irit Katriel, Mark Shannon

儲存下標

a[i] = z

類似於上面的下標特化。

10-25%

Dennis Sweeney

呼叫

f(arg)

C(arg)

呼叫常見的內建(C)函式和型別,如 len()str,直接呼叫其底層的 C 版本。這避免了透過內部呼叫約定。

20%

Mark Shannon, Ken Jin

載入全域性變數

print

len

物件在全域性/內建名稱空間中的索引被快取。載入全域性和內建變數無需名稱空間查詢。

[1]

Mark Shannon

載入屬性

o.attr

類似於載入全域性變數。屬性在類/物件的名稱空間中的索引被快取。在大多數情況下,屬性載入不需要名稱空間查詢。

[2]

Mark Shannon

呼叫方法

o.meth()

方法的實際地址被快取。現在方法載入沒有名稱空間查詢——即使對於具有長繼承鏈的類也是如此。

10-20%

Ken Jin, Mark Shannon

儲存屬性

o.attr = z

類似於載入屬性最佳化。

在 pyperformance 中提高 2%

Mark Shannon

解包序列

*seq

針對常見的容器(例如 listtuple)進行了最佳化。避免了內部呼叫約定。

8%

Brandt Bucher

其他

  • 由於惰性建立的物件名稱空間,物件現在需要更少的記憶體。它們的名稱空間字典現在也更自由地共享鍵。(由 Mark Shannon 在 bpo-45340bpo-40116 中貢獻)。

  • 實現了“零成本”異常,消除了在未引發異常時 try 語句的開銷。(由 Mark Shannon 在 bpo-40222 中貢獻)。

  • 直譯器中更簡潔的異常表示將捕獲異常所需的時間減少了約 10%。(由 Irit Katriel 在 bpo-45711 中貢獻)。

  • re 的正則表示式匹配引擎已部分重構,現在在支援的平臺上使用計算 goto(或“執行緒程式碼”)。因此,Python 3.11 執行 pyperformance 正則表示式基準測試 的速度比 Python 3.10 快 10%。(由 Brandt Bucher 在 gh-91404 中貢獻)。

常見問題

我應該如何編寫程式碼來利用這些加速?

編寫遵循常見最佳實踐的 Pythonic 程式碼;您無需更改程式碼。Faster CPython 專案優化了我們觀察到的常見程式碼模式。

CPython 3.11 會使用更多記憶體嗎?

可能不會;我們預計記憶體使用量不會超過 3.10 的 20%。這可以透過上面提到的幀物件和物件字典的記憶體最佳化來抵消。

我的工作負載中沒有看到任何加速。為什麼?

某些程式碼不會有明顯的收益。如果您的程式碼大部分時間花在 I/O 操作上,或者大部分計算已經在 NumPy 等 C 擴充套件庫中完成,則不會有顯著的加速。該專案目前對純 Python 工作負載的收益最大。

此外,pyperformance 的資料是幾何平均值。即使在 pyperformance 基準測試中,某些基準測試略有減慢,而另一些則加速了近 2 倍!

有 JIT 編譯器嗎?

沒有。我們仍在探索其他最佳化。

關於

Faster CPython 探索了 CPython 的最佳化。主要團隊由微軟資助,全職從事這項工作。Pablo Galindo Salgado 也由 Bloomberg LP 資助,兼職從事該專案。最後,許多貢獻者是社群的志願者。

CPython 位元組碼變更

位元組碼現在包含內聯快取條目,它們以新新增的 CACHE 指令的形式存在。許多操作碼期望後面跟著確切數量的快取,並指示直譯器在執行時跳過它們。填充的快取可以看起來像任意指令,因此在讀取或修改包含加速資料的原始、自適應位元組碼時應格外小心。

新操作碼

替換的操作碼

替換的操作碼

新操作碼

備註

BINARY_*
INPLACE_*

BINARY_OP

將所有數值二元/原地操作碼替換為單個操作碼

CALL_FUNCTION
CALL_FUNCTION_KW
CALL_METHOD
KW_NAMES
PRECALL

將方法的引數移位與關鍵字引數處理解耦;允許更好的呼叫特化

DUP_TOP
DUP_TOP_TWO
ROT_TWO
ROT_THREE
ROT_FOUR
ROT_N

棧操作指令

JUMP_IF_NOT_EXC_MATCH

現在執行檢查但不跳轉

JUMP_ABSOLUTE
POP_JUMP_IF_FALSE
POP_JUMP_IF_TRUE
POP_JUMP_BACKWARD_IF_*
POP_JUMP_FORWARD_IF_*

參見 [3];每個方向的 TRUEFALSENONENOT_NONE 變體

SETUP_WITH
SETUP_ASYNC_WITH

BEFORE_WITH

with 塊設定

更改/移除的操作碼

  • 更改了 MATCH_CLASSMATCH_KEYS,使其不再推送一個額外的布林值來指示成功/失敗。相反,在失敗時,會推送 None 來代替提取值的元組。

  • 更改了處理異常的操作碼,以反映它們現在在棧上表示為一個項,而不是三個項(請參閱 gh-89874)。

  • 移除了 COPY_DICT_WITHOUT_KEYSGEN_STARTPOP_BLOCKSETUP_FINALLYYIELD_FROM

已棄用

本節列出了 Python 3.11 中已棄用的 Python API。

已棄用的 C API 單獨列出

語言/內建

  • 連結 classmethod 描述符(在 bpo-19072 中引入)現在已棄用。它不能再用於包裝其他描述符,例如 property。此功能的核心設計存在缺陷,並導致了一些下游問題。要“傳遞”一個 classmethod,請考慮使用 Python 3.10 中新增的 __wrapped__ 屬性。(由 Raymond Hettinger 在 gh-89519 中貢獻)。

  • 字串和位元組字面量中八進位制轉義符的值大於 0o377(十進位制 255)現在會產生 DeprecationWarning。在未來的 Python 版本中,它們將引發 SyntaxWarning,並最終引發 SyntaxError。(由 Serhiy Storchaka 在 gh-81548 中貢獻)。

  • int()__trunc__() 的委託現在已棄用。當 type(a) 實現了 __trunc__() 但沒有實現 __int__()__index__() 時,呼叫 int(a) 現在會引發 DeprecationWarning。(由 Zackery Spytz 在 bpo-44977 中貢獻)。

模組

  • PEP 594 導致以下模組被棄用,並計劃在 Python 3.13 中移除:

    aifc

    chunk

    msilib

    pipes

    telnetlib

    audioop

    crypt

    nis

    sndhdr

    uu

    cgi

    imghdr

    nntplib

    spwd

    xdrlib

    cgitb

    mailcap

    ossaudiodev

    sunau

    (由 Brett Cannon 在 bpo-47061 和 Victor Stinner 在 gh-68966 中貢獻)。

  • asynchatasyncoresmtpd 模組自 Python 3.6 以來已被棄用。它們的文件和棄用警告已更新,以指出它們將在 Python 3.12 中移除。(由 Hugo van Kemenade 在 bpo-47022 中貢獻)。

  • lib2to3 包和 2to3 工具現已棄用,可能無法解析 Python 3.10 或更高版本。有關詳細資訊,請參見引入新 PEG 解析器的 PEP 617。(由 Victor Stinner 在 bpo-40360 中貢獻)。

  • 未文件化的模組 sre_compilesre_constantssre_parse 現已棄用。(由 Serhiy Storchaka 在 bpo-47152 中貢獻)。

標準庫

  • 以下內容已在 configparser 中自 Python 3.2 以來被棄用。它們的棄用警告現已更新,以指出它們將在 Python 3.12 中移除:

    • configparser.SafeConfigParser

    • configparser.ParsingError.filename 屬性

    • configparser.RawConfigParser.readfp() 方法

    (由 Hugo van Kemenade 在 bpo-45173 中貢獻)。

  • configparser.LegacyInterpolation 自 Python 3.2 以來在文件字串中已棄用,並且未在 configparser 文件中列出。它現在會發出 DeprecationWarning,並將在 Python 3.13 中移除。請改用 configparser.BasicInterpolationconfigparser.ExtendedInterpolation。(由 Hugo van Kemenade 在 bpo-46607 中貢獻)。

  • 較舊的 importlib.resources 函式集已棄用,取而代之的是 Python 3.9 中新增的新函式,並且將在未來的 Python 版本中移除,因為它們不支援包子目錄中的資源:

    • importlib.resources.contents()

    • importlib.resources.is_resource()

    • importlib.resources.open_binary()

    • importlib.resources.open_text()

    • importlib.resources.read_binary()

    • importlib.resources.read_text()

    • importlib.resources.path()

  • locale.getdefaultlocale() 函式已棄用,並將在 Python 3.15 中移除。請改用 locale.setlocale()locale.getpreferredencoding(False)locale.getlocale() 函式。(由 Victor Stinner 在 gh-90817 中貢獻)。

  • locale.resetlocale() 函式已棄用,並將在 Python 3.13 中移除。請改用 locale.setlocale(locale.LC_ALL, "")。(由 Victor Stinner 在 gh-90817 中貢獻)。

  • 現在,針對 正則表示式 中的數字組引用和組名將應用更嚴格的規則。現在,只有 ASCII 數字序列才會被接受為數字引用,並且 bytes 模式和替換字串中的組名只能包含 ASCII 字母、數字和下劃線。目前,違反這些規則的語法會引發棄用警告。(由 Serhiy Storchaka 在 gh-91760 中貢獻)。

  • re 模組中,re.template() 函式以及相應的 re.TEMPLATEre.T 標誌已棄用,因為它們未文件化且缺乏明確的目的。它們將在 Python 3.13 中移除。(由 Serhiy Storchaka 和 Miro Hrončok 在 gh-92728 中貢獻)。

  • turtle.settiltangle() 自 Python 3.1 以來已被棄用;它現在會發出棄用警告,並將在 Python 3.13 中移除。請改用 turtle.tiltangle()(它之前被錯誤地標記為已棄用,現在其文件字串已更正)。(由 Hugo van Kemenade 在 bpo-45837 中貢獻)。

  • typing.Text 僅用於提供 Python 2 和 Python 3 程式碼之間的相容性支援,現已棄用。目前尚未計劃將其移除,但鼓勵使用者在可能的情況下使用 str。(由 Alex Waygood 在 gh-92332 中貢獻)。

  • 用於構建 typing.TypedDict 型別的關鍵字引數語法現已棄用。Python 3.13 中將移除支援。(由 Jingchen Ye 在 gh-90224 中貢獻)。

  • webbrowser.MacOSX 已棄用,並將在 Python 3.13 中移除。它未經測試,未文件化,並且 webbrowser 本身不使用它。(由 Donghee Na 在 bpo-42255 中貢獻)。

  • TestCaseIsolatedAsyncioTestCase 測試方法返回非預設 None 值的行為現在已被棄用。

  • 棄用了以下未正式文件化的 unittest 函式,計劃在 Python 3.13 中移除:

    • unittest.findTestCases()

    • unittest.makeSuite()

    • unittest.getTestCaseNames()

    請改用 TestLoader 方法:

    (由 Erlend E. Aasland 在 bpo-5846 中貢獻)。

  • unittest.TestProgram.usageExit() 被標記為已棄用,將在 3.13 中移除。(由 Carlos Damázio 在 gh-67048 中貢獻)。

計劃在 Python 3.12 中移除

以下 Python API 已在之前的 Python 版本中棄用,並將在 Python 3.12 中移除。

計劃移除的 C API 單獨列出

  • asynchat 模組

  • asyncore 模組

  • 整個 distutils 包

  • imp 模組

  • typing.io 名稱空間

  • typing.re 名稱空間

  • cgi.log()

  • importlib.find_loader()

  • importlib.abc.Loader.module_repr()

  • importlib.abc.MetaPathFinder.find_module()

  • importlib.abc.PathEntryFinder.find_loader()

  • importlib.abc.PathEntryFinder.find_module()

  • importlib.machinery.BuiltinImporter.find_module()

  • importlib.machinery.BuiltinLoader.module_repr()

  • importlib.machinery.FileFinder.find_loader()

  • importlib.machinery.FileFinder.find_module()

  • importlib.machinery.FrozenImporter.find_module()

  • importlib.machinery.FrozenLoader.module_repr()

  • importlib.machinery.PathFinder.find_module()

  • importlib.machinery.WindowsRegistryFinder.find_module()

  • importlib.util.module_for_loader()

  • importlib.util.set_loader_wrapper()

  • importlib.util.set_package_wrapper()

  • pkgutil.ImpImporter

  • pkgutil.ImpLoader

  • pathlib.Path.link_to()

  • sqlite3.enable_shared_cache()

  • sqlite3.OptimizedUnicode()

  • PYTHONTHREADDEBUG 環境變數

  • 以下 unittest 中已棄用的別名:

    已棄用的別名

    方法名

    棄用版本

    failUnless

    assertTrue()

    3.1

    failIf

    assertFalse()

    3.1

    failUnlessEqual

    assertEqual()

    3.1

    failIfEqual

    assertNotEqual()

    3.1

    failUnlessAlmostEqual

    assertAlmostEqual()

    3.1

    failIfAlmostEqual

    assertNotAlmostEqual()

    3.1

    failUnlessRaises

    assertRaises()

    3.1

    assert_

    assertTrue()

    3.2

    assertEquals

    assertEqual()

    3.2

    assertNotEquals

    assertNotEqual()

    3.2

    assertAlmostEquals

    assertAlmostEqual()

    3.2

    assertNotAlmostEquals

    assertNotAlmostEqual()

    3.2

    assertRegexpMatches

    assertRegex()

    3.2

    assertRaisesRegexp

    assertRaisesRegex()

    3.2

    assertNotRegexpMatches

    assertNotRegex()

    3.5

已移除

本節列出了 Python 3.11 中已移除的 Python API。

已移除的 C API 單獨列出

  • 移除了 @asyncio.coroutine() 裝飾器,該裝飾器曾使基於舊版生成器的協程能夠與 async / await 程式碼相容。此函式自 Python 3.8 起已被棄用,並原定於 Python 3.10 中移除。請改用 async def。(由 Illia Volochii 在 bpo-43216 中貢獻。)

  • 移除了 asyncio.coroutines.CoroWrapper,該類用於在除錯模式下包裝基於舊版生成器的協程物件。(由 Illia Volochii 在 bpo-43216 中貢獻。)

  • 由於重大的安全問題,asyncio.loop.create_datagram_endpoint()reuse_address 引數(在 Python 3.9 中停用)現在已完全移除。這是由於 SO_REUSEADDR 套接字選項在 UDP 中的行為所致。(由 Hugo van Kemenade 在 bpo-45129 中貢獻。)

  • 移除了 binhex 模組,該模組在 Python 3.9 中已被棄用。同時移除了相關且同樣已被棄用的 binascii 函式:

    • binascii.a2b_hqx()

    • binascii.b2a_hqx()

    • binascii.rlecode_hqx()

    • binascii.rldecode_hqx()

    binascii.crc_hqx() 函式仍然可用。

    (由 Victor Stinner 在 bpo-45085 中貢獻。)

  • 移除了 distutilsbdist_msi 命令,該命令在 Python 3.9 中已被棄用。請改用 bdist_wheel (wheel 包)。(由 Hugo van Kemenade 在 bpo-45124 中貢獻。)

  • 移除了 xml.dom.pulldom.DOMEventStreamwsgiref.util.FileWrapperfileinput.FileInput__getitem__() 方法,這些方法自 Python 3.9 起已被棄用。(由 Hugo van Kemenade 在 bpo-45132 中貢獻。)

  • 移除了已棄用的 gettext 函式 lgettext()ldgettext()lngettext()ldngettext()。同時移除了 bind_textdomain_codeset() 函式、NullTranslations.output_charset()NullTranslations.set_output_charset() 方法,以及 translation()install()codeset 引數,因為它們僅用於 l*gettext() 函式。(由 Donghee Na 和 Serhiy Storchaka 在 bpo-44235 中貢獻。)

  • inspect 模組中移除:

    (由 Hugo van Kemenade 在 bpo-45320 中貢獻。)

  • pathlib.PurePath 中移除了 __class_getitem__() 方法,因為它未被使用且在早期版本中因錯誤而新增。(由 Nikita Sobolev 在 bpo-46483 中貢獻。)

  • 移除了 smtpd 模組中的 MailmanProxy 類,因為它在沒有外部 mailman 包的情況下無法使用。(由 Donghee Na 在 bpo-35800 中貢獻。)

  • 移除了 _tkinter.TkappType 中已棄用的 split() 方法。(由 Erlend E. Aasland 在 bpo-38371 中貢獻。)

  • 移除了 unittest 發現功能中的名稱空間包支援。該功能在 Python 3.4 中引入,但自 Python 3.7 起已損壞。(由 Inada Naoki 在 bpo-23882 中貢獻。)

  • 移除了未文件化的私有 float.__set_format__() 方法,該方法在 Python 3.7 中曾被稱為 float.__setformat__()。其文件字串寫道:“您可能不想使用此函式。它主要用於 Python 的測試套件。”(由 Victor Stinner 在 bpo-46852 中貢獻。)

  • --experimental-isolated-subinterpreters 配置標誌(以及相應的 EXPERIMENTAL_ISOLATED_SUBINTERPRETERS 宏)已被移除。

  • Pynche —— Pythonic自然色彩和色調編輯器 —— 已從 Tools/scripts 移出,並 獨立於 Python 原始碼樹進行開發

移植到 Python 3.11

本節列出了之前描述的更改以及 Python API 中可能需要更改您的 Python 程式碼的其他錯誤修復。

C API 的移植說明 單獨列出

構建更改

  • CPython 現在對 WebAssembly 平臺 Emscripten (wasm32-unknown-emscripten,即瀏覽器中的 Python) 和 WebAssembly 系統介面 (WASI) (wasm32-unknown-wasi) 具有 PEP 11 Tier 3 支援 的交叉編譯功能。此工作受到 Pyodide 等先前工作的啟發。這些平臺提供了 POSIX API 的有限子集;與網路、程序、執行緒、訊號、mmap 和使用者/組相關的 Python 標準庫功能和模組不可用或不起作用。(Emscripten 由 Christian Heimes 和 Ethan Smith 在 gh-84461 中貢獻,WASI 由 Christian Heimes 在 gh-90473 中貢獻;平臺在 gh-95085 中得到推廣)

  • 構建 CPython 現在需要

  • 已移除 Py_NO_NAN 宏。由於 CPython 現在需要 IEEE 754 浮點數,因此 NaN 值始終可用。(由 Victor Stinner 在 bpo-46656 中貢獻。)

  • tkinter 包現在需要 Tcl/Tk 8.5.12 或更高版本。(由 Serhiy Storchaka 在 bpo-46996 中貢獻。)

  • 大多數 stdlib 擴充套件模組的構建依賴項、編譯器標誌和連結器標誌現在由 configure 檢測。libffi、libnsl、libsqlite3、zlib、bzip2、liblzma、libcrypt、Tcl/Tk 和 uuid 標誌由 pkg-config(如果可用)檢測。tkinter 現在需要 pkg-config 命令來檢測 Tcl/Tk 標頭檔案和庫的開發設定。(由 Christian Heimes 和 Erlend Egeberg Aasland 在 bpo-45847bpo-45747bpo-45763 中貢獻。)

  • libpython 不再連結 libcrypt。(由 Mike Gilbert 在 bpo-45433 中貢獻。)

  • CPython 現在可以透過向 --with-lto 傳遞 thin 選項,即 --with-lto=thin,來使用 ThinLTO 選項構建。(由 Donghee Na 和 Brett Holman 在 bpo-44340 中貢獻。)

  • 現在可以停用物件結構的空閒列表。新的 configure 選項 --without-freelists 可用於停用除空元組單例之外的所有空閒列表。(由 Christian Heimes 在 bpo-45522 中貢獻。)

  • Modules/SetupModules/makesetup 已得到改進和整合。現在可以透過 makesetup 構建擴充套件模組。除了一些測試模組外,所有模組都可以靜態連結到主二進位制檔案或庫中。(由 Brett Cannon 和 Christian Heimes 在 bpo-45548bpo-45570bpo-45571bpo-43974 中貢獻。)

    備註

    使用環境變數 TCLTK_CFLAGSTCLTK_LIBS 手動指定 Tcl/Tk 標頭檔案和庫的位置。configure 選項 --with-tcltk-includes--with-tcltk-libs 已被移除。

    在 RHEL 7 和 CentOS 7 上,開發包不提供 tcl.pctk.pc;請使用 TCLTK_LIBS="-ltk8.5 -ltkstub8.5 -ltcl8.5"。目錄 Misc/rhel7 包含 .pc 檔案以及如何使用 RHEL 7 和 CentOS 7 的 Tcl/Tk 和 OpenSSL 構建 Python 的說明。

  • CPython 現在預設將對 Python int 實現使用 30 位數字。此前,預設是在 SIZEOF_VOID_P >= 8 的平臺上使用 30 位數字,否則使用 15 位數字。仍然可以透過配置指令碼的 --enable-big-digits 選項或(對於 Windows)PC/pyconfig.h 中的 PYLONG_BITS_IN_DIGIT 變數顯式請求使用 15 位數字,但此選項可能會在未來的某個時候移除。(由 Mark Dickinson 在 bpo-45569 中貢獻。)

C API 更改

新功能

移植到 Python 3.11

  • 一些宏已轉換為靜態行內函數,以避免 宏陷阱。此更改對使用者而言應基本透明,因為替換函式將把其引數轉換為預期型別,以避免由於靜態型別檢查導致的編譯器警告。然而,當受限 C API 設定為 >=3.11 時,這些轉換不會進行,呼叫者需要將引數轉換為預期型別。有關更多詳細資訊,請參閱 PEP 670。(由 Victor Stinner 和 Erlend E. Aasland 在 gh-89653 中貢獻。)

  • PyErr_SetExcInfo() 不再使用 typetraceback 引數,直譯器現在從異常例項(value 引數)派生這些值。該函式仍然竊取所有三個引數的引用。(由 Irit Katriel 在 bpo-45711 中貢獻。)

  • PyErr_GetExcInfo() 現在從異常例項(value 欄位)派生結果的 typetraceback 欄位。(由 Irit Katriel 在 bpo-45711 中貢獻。)

  • _frozen 有一個新的 is_package 欄位,用於指示凍結模組是否為包。此前,size 欄位中的負值是指示符。現在 size 將只使用非負值。(由 Kumar Aditya 在 bpo-46608 中貢獻。)

  • _PyFrameEvalFunction() 現在將其第二個引數從 PyFrameObject* 改為 _PyInterpreterFrame*。有關如何使用此函式指標型別的更多詳細資訊,請參閱 PEP 523

  • PyCode_New()PyCode_NewWithPosOnlyArgs() 現在接受一個額外的 exception_table 引數。應儘可能避免使用這些函式。要獲取自定義程式碼物件:使用編譯器建立一個程式碼物件,然後使用 replace 方法獲取修改後的版本。

  • PyCodeObject 不再有 co_codeco_varnamesco_cellvarsco_freevars 欄位。請改用 PyCode_GetCode()PyCode_GetVarnames()PyCode_GetCellvars()PyCode_GetFreevars() 分別透過 C API 訪問它們。(由 Brandt Bucher 在 bpo-46841 和 Ken Jin 在 gh-92154gh-94936 中貢獻。)

  • 舊的垃圾桶宏 (Py_TRASHCAN_SAFE_BEGIN/Py_TRASHCAN_SAFE_END) 現已棄用。它們應替換為新的宏 Py_TRASHCAN_BEGINPy_TRASHCAN_END

    一個具有舊宏的 tp_dealloc 函式,例如

    static void
    mytype_dealloc(mytype *p)
    {
        PyObject_GC_UnTrack(p);
        Py_TRASHCAN_SAFE_BEGIN(p);
        ...
        Py_TRASHCAN_SAFE_END
    }
    

    應按如下方式遷移到新宏

    static void
    mytype_dealloc(mytype *p)
    {
        PyObject_GC_UnTrack(p);
        Py_TRASHCAN_BEGIN(p, mytype_dealloc)
        ...
        Py_TRASHCAN_END
    }
    

    請注意,Py_TRASHCAN_BEGIN 有一個第二個引數,它應該是它所在的解除分配函式。

    為了在相同的程式碼庫中支援舊的 Python 版本,您可以定義以下宏並在整個程式碼中使用它們(鳴謝:這些是從 mypy 程式碼庫複製的)

    #if PY_VERSION_HEX >= 0x03080000
    #  define CPy_TRASHCAN_BEGIN(op, dealloc) Py_TRASHCAN_BEGIN(op, dealloc)
    #  define CPy_TRASHCAN_END(op) Py_TRASHCAN_END
    #else
    #  define CPy_TRASHCAN_BEGIN(op, dealloc) Py_TRASHCAN_SAFE_BEGIN(op)
    #  define CPy_TRASHCAN_END(op) Py_TRASHCAN_SAFE_END(op)
    #endif
    
  • 如果型別定義時設定了 Py_TPFLAGS_HAVE_GC 標誌但沒有遍歷函式(PyTypeObject.tp_traverse),PyType_Ready() 函式現在會引發錯誤。(由 Victor Stinner 在 bpo-44263 中貢獻。)

  • 具有 Py_TPFLAGS_IMMUTABLETYPE 標誌的堆型別現在可以繼承 PEP 590 vectorcall 協議。此前,這僅適用於 靜態型別。(由 Erlend E. Aasland 在 bpo-43908 中貢獻)

  • 由於 Py_TYPE() 已更改為內聯靜態函式,Py_TYPE(obj) = new_type 必須替換為 Py_SET_TYPE(obj, new_type):請參閱 Py_SET_TYPE() 函式(自 Python 3.9 起可用)。為了向後相容,可以使用此宏

    #if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE)
    static inline void _Py_SET_TYPE(PyObject *ob, PyTypeObject *type)
    { ob->ob_type = type; }
    #define Py_SET_TYPE(ob, type) _Py_SET_TYPE((PyObject*)(ob), type)
    #endif
    

    (由 Victor Stinner 在 bpo-39573 中貢獻。)

  • 由於 Py_SIZE() 已更改為內聯靜態函式,Py_SIZE(obj) = new_size 必須替換為 Py_SET_SIZE(obj, new_size):請參閱 Py_SET_SIZE() 函式(自 Python 3.9 起可用)。為了向後相容,可以使用此宏

    #if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_SIZE)
    static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size)
    { ob->ob_size = size; }
    #define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject*)(ob), size)
    #endif
    

    (由 Victor Stinner 在 bpo-39573 中貢獻。)

  • Py_LIMITED_API 宏設定為 0x030b0000 (Python 3.11) 或更高版本時,<Python.h> 不再包含標頭檔案 <stdlib.h><stdio.h><errno.h><string.h>。C 擴充套件應在 #include <Python.h> 之後顯式包含這些標頭檔案。(由 Victor Stinner 在 bpo-45434 中貢獻。)

  • 非受限 API 檔案 cellobject.hclassobject.hcode.hcontext.hfuncobject.hgenobject.hlongintrepr.h 已移至 Include/cpython 目錄。此外,eval.h 標頭檔案已被移除。這些檔案不應直接包含,因為它們已包含在 Python.h 中:包含檔案。如果已直接包含它們,請考慮改用 Python.h。(由 Victor Stinner 在 bpo-35134 中貢獻。)

  • PyUnicode_CHECK_INTERNED() 宏已從受限 C API 中排除。它在那裡從未可用,因為它使用了受限 C API 中不可用的內部結構。(由 Victor Stinner 在 bpo-46007 中貢獻。)

  • 以下幀函式和型別現在可直接透過 #include <Python.h> 使用,不再需要新增 #include <frameobject.h>

    (由 Victor Stinner 在 gh-93937 中貢獻。)

  • PyFrameObject 結構成員已從公共 C API 中移除。

    雖然文件指出 PyFrameObject 欄位可能隨時更改,但它們已穩定很長時間,並被一些流行的擴充套件使用。

    在 Python 3.11 中,幀結構被重組以實現效能最佳化。一些欄位完全移除,因為它們是舊實現中的細節。

    PyFrameObject 欄位

    Python 幀物件現在是惰性建立的。一個副作用是 f_back 成員不應直接訪問,因為它的值現在也是惰性計算的。必須呼叫 PyFrame_GetBack() 函式。

    直接訪問 f_locals 的偵錯程式 必須 呼叫 PyFrame_GetLocals()。它們不再需要呼叫 PyFrame_FastToLocalsWithError()PyFrame_LocalsToFast(),實際上它們不應該呼叫這些函式。幀的必要更新現在由虛擬機器管理。

    在 Python 3.8 及更早版本上定義 PyFrame_GetCode() 的程式碼

    #if PY_VERSION_HEX < 0x030900B1
    static inline PyCodeObject* PyFrame_GetCode(PyFrameObject *frame)
    {
        Py_INCREF(frame->f_code);
        return frame->f_code;
    }
    #endif
    

    在 Python 3.8 及更早版本上定義 PyFrame_GetBack() 的程式碼

    #if PY_VERSION_HEX < 0x030900B1
    static inline PyFrameObject* PyFrame_GetBack(PyFrameObject *frame)
    {
        Py_XINCREF(frame->f_back);
        return frame->f_back;
    }
    #endif
    

    或者使用 pythoncapi_compat 專案 在舊版 Python 上獲取這兩個函式。

  • PyThreadState 結構成員的更改

    在 Python 3.8 及更早版本上定義 PyThreadState_GetFrame() 的程式碼

    #if PY_VERSION_HEX < 0x030900B1
    static inline PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate)
    {
        Py_XINCREF(tstate->frame);
        return tstate->frame;
    }
    #endif
    

    在 Python 3.10 及更早版本上定義 PyThreadState_EnterTracing()PyThreadState_LeaveTracing() 的程式碼

    #if PY_VERSION_HEX < 0x030B00A2
    static inline void PyThreadState_EnterTracing(PyThreadState *tstate)
    {
        tstate->tracing++;
    #if PY_VERSION_HEX >= 0x030A00A1
        tstate->cframe->use_tracing = 0;
    #else
        tstate->use_tracing = 0;
    #endif
    }
    
    static inline void PyThreadState_LeaveTracing(PyThreadState *tstate)
    {
        int use_tracing = (tstate->c_tracefunc != NULL || tstate->c_profilefunc != NULL);
        tstate->tracing--;
    #if PY_VERSION_HEX >= 0x030A00A1
        tstate->cframe->use_tracing = use_tracing;
    #else
        tstate->use_tracing = use_tracing;
    #endif
    }
    #endif
    

    或者使用 pythoncapi-compat 專案 在舊版 Python 上獲取這些函式。

  • 鼓勵分發商使用最佳化的 Blake2 庫 libb2 構建 Python。

  • PyConfig.module_search_paths_set 欄位現在必須設定為 1,以便初始化使用 PyConfig.module_search_paths 初始化 sys.path。否則,初始化將重新計算路徑並替換新增到 module_search_paths 的任何值。

  • PyConfig_Read() 不再計算初始搜尋路徑,也不會填充任何值到 PyConfig.module_search_paths。要計算預設路徑並進行修改,請完成初始化並使用 PySys_GetObject()sys.path 作為 Python 列表物件檢索並直接修改它。

已棄用

  • 棄用以下函式以配置 Python 初始化

    • PySys_AddWarnOptionUnicode()

    • PySys_AddWarnOption()

    • PySys_AddXOption()

    • PySys_HasWarnOptions()

    • PySys_SetArgvEx()

    • PySys_SetArgv()

    • PySys_SetPath()

    • Py_SetPath()

    • Py_SetProgramName()

    • Py_SetPythonHome()

    • Py_SetStandardStreamEncoding()

    • _Py_SetProgramFullPath()

    請改用 Python 初始化配置 的新 PyConfig API(PEP 587)。(由 Victor Stinner 在 gh-88279 中貢獻。)

  • 棄用 PyBytesObjectob_shash 成員。請改用 PyObject_Hash()。(由 Inada Naoki 在 bpo-46864 中貢獻。)

Python 3.12 中待移除

以下 C API 已在早期的 Python 版本中棄用,並將在 Python 3.12 中移除。

  • PyUnicode_AS_DATA()

  • PyUnicode_AS_UNICODE()

  • PyUnicode_AsUnicodeAndSize()

  • PyUnicode_AsUnicode()

  • PyUnicode_FromUnicode()

  • PyUnicode_GET_DATA_SIZE()

  • PyUnicode_GET_SIZE()

  • PyUnicode_GetSize()

  • PyUnicode_IS_COMPACT()

  • PyUnicode_IS_READY()

  • PyUnicode_READY()

  • PyUnicode_WSTR_LENGTH()

  • _PyUnicode_AsUnicode()

  • PyUnicode_WCHAR_KIND

  • PyUnicodeObject

  • PyUnicode_InternImmortal()

已移除

  • PyFrame_BlockSetup()PyFrame_BlockPop() 已被移除。(由 Mark Shannon 在 bpo-40222 中貢獻。)

  • 移除以下使用 errno 變數的數學宏

    • Py_ADJUST_ERANGE1()

    • Py_ADJUST_ERANGE2()

    • Py_OVERFLOWED()

    • Py_SET_ERANGE_IF_OVERFLOW()

    • Py_SET_ERRNO_ON_MATH_ERROR()

    (由 Victor Stinner 在 bpo-45412 中貢獻。)

  • 移除 Py_UNICODE_COPY()Py_UNICODE_FILL() 宏,它們自 Python 3.3 起已被棄用。請改用 PyUnicode_CopyCharacters()memcpy() (wchar_t* 字串),以及 PyUnicode_Fill() 函式。(由 Victor Stinner 在 bpo-41123 中貢獻。)

  • 移除 pystrhex.h 標頭檔案。它只包含私有函式。C 擴充套件只應包含主要的 <Python.h> 標頭檔案。(由 Victor Stinner 在 bpo-45434 中貢獻。)

  • 移除 Py_FORCE_DOUBLE() 宏。它曾被 Py_IS_INFINITY() 宏使用。(由 Victor Stinner 在 bpo-45440 中貢獻。)

  • Py_LIMITED_API 定義時,以下專案不再可用

    這些不屬於 受限 API

    (由 Victor Stinner 在 bpo-45474 中貢獻。)

  • 從受限 C API 中排除 PyWeakref_GET_OBJECT()。它從未起作用,因為 PyWeakReference 結構在受限 C API 中是不透明的。(由 Victor Stinner 在 bpo-35134 中貢獻。)

  • 移除 PyHeapType_GET_MEMBERS() 宏。它因錯誤地暴露在公共 C API 中,它只能在 Python 內部使用。請改用 PyTypeObject.tp_members 成員。(由 Victor Stinner 在 bpo-40170 中貢獻。)

  • 移除 HAVE_PY_SET_53BIT_PRECISION 宏(已移至內部 C API)。(由 Victor Stinner 在 bpo-45412 中貢獻。)

  • 移除 Py_UNICODE 編碼器 API,因為它們自 Python 3.3 起已被棄用,使用較少且相對於推薦的替代方案效率低下。

    已移除的函式有:

    • PyUnicode_Encode()

    • PyUnicode_EncodeASCII()

    • PyUnicode_EncodeLatin1()

    • PyUnicode_EncodeUTF7()

    • PyUnicode_EncodeUTF8()

    • PyUnicode_EncodeUTF16()

    • PyUnicode_EncodeUTF32()

    • PyUnicode_EncodeUnicodeEscape()

    • PyUnicode_EncodeRawUnicodeEscape()

    • PyUnicode_EncodeCharmap()

    • PyUnicode_TranslateCharmap()

    • PyUnicode_EncodeDecimal()

    • PyUnicode_TransformDecimalToASCII()

    有關詳細資訊和 遷移指南,請參閱 PEP 624。(由 Inada Naoki 在 bpo-44029 中貢獻。)

3.11.4 中的顯著更改

tarfile

  • tarfile 中的提取方法和 shutil.unpack_archive() 現在有一個新的 filter 引數,允許限制 tar 功能,這些功能可能令人意外或危險,例如在目標目錄之外建立檔案。有關詳細資訊,請參閱 提取過濾器。在 Python 3.12 中,不帶 filter 引數的使用將顯示 DeprecationWarning。在 Python 3.14 中,預設值將切換為 'data'。(由 Petr Viktorin 在 PEP 706 中貢獻。)

3.11.5 中的顯著更改

OpenSSL

  • python.org 提供的 Windows 構建和 macOS 安裝程式現在使用 OpenSSL 3.0。