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 中包含的 Windows 版 Python 啟動器的副本已得到顯著更新。它現在支援 PEP 514 中定義的公司/標籤語法,使用 -V:<公司>/<標籤> 引數而不是有限的 -<主版本>.<次版本>。這允許啟動 PythonCore(託管在 python.org 上的)以外的發行版。

當使用 -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。這確保只有 stdlib 和已安裝的模組被 import 拾取,並避免無意或惡意地使用本地(通常是使用者可寫的)目錄中的模組來覆蓋模組。(由 Victor Stinner 在 gh-57684 中貢獻。)

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

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

其他 CPython 實現更改

  • 實現了 complex 的特殊方法 __complex__()bytes 的特殊方法 __bytes__(),以支援 typing.SupportsComplextyping.SupportsBytes 協議。(由 Mark Dickinson 和 Donghee Na 在 bpo-24234 中貢獻。)

  • 添加了 siphash13 作為新的內部雜湊演算法。它具有與 siphash24 相似的安全屬性,但對於長輸入來說速度稍快。strbytes 和一些其他型別現在使用它作為 hash() 的預設演算法。PEP 552 基於雜湊值的 .pyc 檔案 現在也使用 siphash13。(由 Inada Naoki 在 bpo-29410 中貢獻。)

  • 當使用不帶引數的 raise 語句重新引發活動異常時,附加到此異常的回溯現在始終為 sys.exc_info()[1].__traceback__。這意味著在當前的 except 子句中對回溯所做的更改將反映在重新引發的異常中。(由 Irit Katriel 在 bpo-45711 中貢獻。)

  • 直譯器狀態對已處理異常的表示(又名 exc_info_PyErr_StackItem)現在只有 exc_value 欄位;exc_typeexc_traceback 已被刪除,因為它們可以從 exc_value 推匯出來。(由 Irit Katriel 在 bpo-45711 中貢獻。)

  • 為 Windows 安裝程式添加了一個新的 命令列選項AppendPath。它的行為與 PrependPath 類似,但它是追加而不是前置安裝目錄和指令碼目錄。(由 Bastian Neuburger 在 bpo-44934 中貢獻。)

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

  • 現在,--help 選項的輸出符合 50 行/80 列。關於 Python 環境變數-X 選項的資訊現在可以使用相應的 --help-env--help-xoptions 標誌獲得,並且可以使用新的 --help-all 標誌獲得。(由 Éric Araujo 在 bpo-46142 中貢獻。)

  • 在 2(二進位制)、4、8(八進位制)、16(十六進位制)或 32 之外的進制中,將 intstr 之間進行轉換時,如果字串形式的數字位數超過限制,現在會引發 ValueError,以避免由於演算法複雜度而導致的潛在拒絕服務攻擊。這是對 CVE 2020-10735 的緩解措施。此限制可以透過環境變數、命令列標誌或 sys API 進行配置或停用。請參閱 整數字符串轉換長度限制 文件。字串形式的預設限制是 4300 位數字。

新模組

改進的模組

asyncio

contextlib

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

dataclasses

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

datetime

enum

  • EnumMeta 重新命名為 EnumType(保留 EnumMeta 作為別名)。

  • 添加了 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

  • 支援從字串初始化 FractionPEP 515 樣式。(由 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

  • 當使用 mtime=0 引數時,gzip.compress() 函式現在更快,因為它將壓縮完全委託給單個 zlib.compress() 操作。此更改有一個副作用:gzip 檔案頭在其頭部包含一個“OS”位元組。傳統上,gzip 模組始終將其設定為值 255,表示“未知”。現在,當使用 mtime=0compress() 時,它可能會被 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

  • 為 NetBSD 新增 CAN 套接字支援。(由 Thomas Klausner 在 bpo-30512 中貢獻。)

  • 如果連線失敗,create_connection() 有一個選項可以引發一個包含所有錯誤的 ExceptionGroup,而不是隻引發最後一個錯誤。(由 Irit Katriel 在 bpo-29980 中貢獻。)

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_venvnt_venvvenv),當 Python 建立新的虛擬環境或從虛擬環境中執行時使用。前兩種方案(posix_venvnt_venv)是特定於作業系統的,分別用於非 Windows 和 Windows,venv 本質上是根據 Python 執行的作業系統對其中一種方案的別名。這對於修改 sysconfig.get_preferred_scheme() 的下游發行商很有用。建立新虛擬環境的第三方程式碼應使用新的 venv 安裝方案來確定路徑,就像 venv 一樣。(由 Miro Hrončok 在 bpo-45413 中貢獻。)

tempfile

threading

time

  • 在 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(),它返回 Tcl 庫的精確版本,作為一個類似於 sys.version_info 的命名元組。(由 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 的子類化。 這有助於避免與高度動態的類(例如 mocks)相關的型別檢查器錯誤。(由 Shantanu Jain 在 gh-91154 中貢獻。)

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

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

  • __init__() 方法現在保留 Protocol 子類。(由 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() 不再將 Optional 新增到預設值為 None 的引數。(由 Nikita Sobolev 在 gh-90353 中貢獻。)

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

  • typing.no_type_check() 不再修改外部類和函式。 它現在還正確地將 classmethod 標記為不進行型別檢查。(由 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

  • 添加了對指定成員名稱編碼的支援,用於在 ZipFile 的目錄和檔案標頭中讀取元資料。(由 Stephen J. Turnbull 和 Serhiy Storchaka 在 bpo-28080 中貢獻。)

  • 添加了 ZipFile.mkdir(),用於在 ZIP 存檔中建立新目錄。(由 Sam Ezeh 在 gh-49083 中貢獻。)

  • zipfile.Path 添加了 stemsuffixsuffixes。(由 Miguel Brito 在 gh-88261 中貢獻。)

最佳化

本節介紹獨立於 Faster CPython 專案的特定最佳化,該專案將在其自己的部分中介紹。

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

  • 整數除法(//)更適合編譯器進行最佳化。當使用小於 2**30 的值去除一個 int 時,在 x86-64 架構上速度現在提升了約 20%。(由 Gregory P. Smith 和 Tim Peters 在 gh-90564 中貢獻。)

  • sum() 函式現在對於小於 2**30 的整數快了近 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 中貢獻。)

  • 當透過 UDP 傳輸大檔案時,使用 asyncio.DatagramProtocol 的速度現在提升了幾個數量級,對於大約 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 比 CPython 3.10 平均快 25%,這是透過 pyperformance 基準測試套件測量的。 根據您的工作負載,整體加速可能在 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 中貢獻。)

內聯 Python 函式呼叫

在 Python 函式呼叫期間,Python 將呼叫一個評估 C 函式來解釋該函式的程式碼。 這實際上將純 Python 遞迴限制為 C 堆疊安全範圍內的遞迴。

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

現在,大多數 Python 函式呼叫都不佔用 C 堆疊空間,從而加快了速度。 在像 fibonacci 或階乘這樣的簡單遞迴函式中,我們觀察到了 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)

對諸如 len()str 等常用內建 (C) 函式和型別的呼叫會直接呼叫其底層的 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 的最佳化。主要團隊由 Microsoft 資助全職從事這項工作。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 中貢獻。)

標準庫

  • 自 Python 3.2 以來,以下內容在 configparser 中已棄用。它們的棄用警告現在已更新,以說明它們將在 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 中停用,現在已完全移除。 這是由於 UDP 中套接字選項 SO_REUSEADDR 的行為所致。(由 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 中貢獻。)

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

  • 移除了 __getitem__() 方法,這些方法來自 xml.dom.pulldom.DOMEventStreamwsgiref.util.FileWrapperfileinput.FileInput,它們自 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.TkappTypesplit() 方法。(由 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 第 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。)

  • 現在由 configure 檢測大多數 stdlib 擴充套件模組的構建依賴項、編譯器標誌和連結器標誌。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 現在可以透過將 thin 傳遞給 --with-lto 來使用 ThinLTO 選項進行構建,即 --with-lto=thin。(由 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() 現在將 _PyInterpreterFrame* 作為其第二個引數,而不是 PyFrameObject*。有關如何使用此函式指標型別的更多詳細資訊,請參閱 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 標誌但沒有 traverse 函式 (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()

    使用 PyConfig API,即 Python 初始化配置 來代替 (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()。它從未起作用,因為在受限 C API 中 PyWeakReference 結構是不透明的。(由 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

  • tarfileshutil.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。