Python 3.10 有什麼新功能

編輯者:

Pablo Galindo Salgado

本文介紹了 Python 3.10 與 3.9 相比的新功能。Python 3.10 於 2021 年 10 月 4 日發布。有關完整詳細資訊,請參閱 changelog

摘要 -- 發布重點

新增語法特性:

  • PEP 634,結構模式匹配 (Structural Pattern Matching):規範

  • PEP 635,結構模式匹配:動機和基本原理

  • PEP 636,結構模式匹配:教學

  • bpo-12782,現在正式允許帶括號的情境管理器 (context manager)。

標準函式庫中的新功能:

  • PEP 618,新增可選的長度檢查到 zip。

直譯器改進:

  • PEP 626,用於除錯和其他工具的精確列號。

新的 typing 功能:

  • PEP 604,允許將聯集型別 (union types) 寫為 X | Y

  • PEP 612,參數規範變數 (Parameter Specification Variables)

  • PEP 613,顯式型別別名 (Explicit Type Aliases)

  • PEP 647,使用者定義的型別防護 (User-Defined Type Guards)

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

  • PEP 644,需要 OpenSSL 1.1.1 或更高版本

  • PEP 632,棄用 distutils 模組。

  • PEP 623,棄用並準備刪除 PyUnicodeObject 中的 wstr 成員。

  • PEP 624,刪除 Py_UNICODE 編碼器 API

  • PEP 597,新增可選的 EncodingWarning

新功能

帶括號的情境管理器

現在支援使用成對的括號來將多個情境管理器以數行表示。這允許了與過去的引入陳述式 (import statement) 類似的方法來格式化一組多行的情境管理器集合。例如,以下範例現在都是有效的:

with (CtxManager() as example):
    ...

with (
    CtxManager1(),
    CtxManager2()
):
    ...

with (CtxManager1() as example,
      CtxManager2()):
    ...

with (CtxManager1(),
      CtxManager2() as example):
    ...

with (
    CtxManager1() as example1,
    CtxManager2() as example2
):
    ...

也可以在封閉群組的末尾使用逗號:

with (
    CtxManager1() as example1,
    CtxManager2() as example2,
    CtxManager3() as example3,
):
    ...

此新語法使用新剖析器的非 LL(1) 功能。檢查 PEP 617 了解更多詳細資訊。

(由 Guido van Rossum、Pablo Galindo 和 Lysandros Nikolaou 在 bpo-12782bpo-40334 中貢獻。)

更好的錯誤訊息

SyntaxErrors

當剖析包含未成對括號或方括號的程式碼時,直譯器現在會包含未成對括號的位置,而不是顯示 SyntaxError: unexpected EOF while parsing 或指向某些不正確的位置。例如,以下程式碼(注意未閉合的 { ):

expected = {9: 1, 18: 2, 19: 2, 27: 3, 28: 3, 29: 3, 36: 4, 37: 4,
            38: 4, 39: 4, 45: 5, 46: 5, 47: 5, 48: 5, 49: 5, 54: 6,
some_other_code = foo()

以前版本的直譯器會在奇怪的地方顯示有語法錯誤:

File "example.py", line 3
    some_other_code = foo()
                    ^
SyntaxError: invalid syntax

但在 Python 3.10 中,會發出一個資訊更豐富的錯誤:

File "example.py", line 1
    expected = {9: 1, 18: 2, 19: 2, 27: 3, 28: 3, 29: 3, 36: 4, 37: 4,
               ^
SyntaxError: '{' was never closed

同樣地,涉及未成對字串字面值(單引號和三引號)的錯誤現在會指向字串的開頭,而不是報告 EOF/EOL。

這些改進是受到 PyPy 直譯器的啟發。

(由 Pablo Galindo 在 bpo-42864 和 Batuhan Taskaya 在 bpo-40176 中貢獻。)

直譯器引發的 SyntaxError 例外現在會突顯 (highlight) 構成語法錯誤之運算式的完整錯誤範圍,而不僅是檢測到問題的位置。如此一來,過去(像 Python 3.10 之前)的:

>>> foo(x, z for z in range(10), t, w)
  File "<stdin>", line 1
    foo(x, z for z in range(10), t, w)
           ^
SyntaxError: Generator expression must be parenthesized

現在 Python 3.10 則會將例外顯示為:

>>> foo(x, z for z in range(10), t, w)
  File "<stdin>", line 1
    foo(x, z for z in range(10), t, w)
           ^^^^^^^^^^^^^^^^^^^^
SyntaxError: Generator expression must be parenthesized

此改進由 Pablo Galindo 在 bpo-43914 中貢獻。

已合併了大量針對 SyntaxError 例外的新專用訊息。一些最值得注意的如下:

  • 在區塊之前缺少 ::

    >>> if rocket.position > event_horizon
      File "<stdin>", line 1
        if rocket.position > event_horizon
                                          ^
    SyntaxError: expected ':'
    

    (由 Pablo Galindo 在 bpo-42997 中貢獻。)

  • 綜合運算目標中未加括號的元組:

    >>> {x,y for x,y in zip('abcd', '1234')}
      File "<stdin>", line 1
        {x,y for x,y in zip('abcd', '1234')}
         ^
    SyntaxError: did you forget parentheses around the comprehension target?
    

    (由 Pablo Galindo 在 bpo-43017 中貢獻。)

  • 容器字面值 (collection literals) 中和運算式之間缺少逗號:

    >>> items = {
    ... x: 1,
    ... y: 2
    ... z: 3,
      File "<stdin>", line 3
        y: 2
           ^
    SyntaxError: invalid syntax. Perhaps you forgot a comma?
    

    (由 Pablo Galindo 在 bpo-43822 中貢獻。)

  • 不帶括號的多個例外型別:

    >>> try:
    ...     build_dyson_sphere()
    ... except NotEnoughScienceError, NotEnoughResourcesError:
      File "<stdin>", line 3
        except NotEnoughScienceError, NotEnoughResourcesError:
               ^
    SyntaxError: multiple exception types must be parenthesized
    

    (由 Pablo Galindo 在 bpo-43149 中貢獻。)

  • 字典字面值中缺少 : 和值:

    >>> values = {
    ... x: 1,
    ... y: 2,
    ... z:
    ... }
      File "<stdin>", line 4
        z:
         ^
    SyntaxError: expression expected after dictionary key and ':'
    
    >>> values = {x:1, y:2, z w:3}
      File "<stdin>", line 1
        values = {x:1, y:2, z w:3}
                            ^
    SyntaxError: ':' expected after dictionary key
    

    (由 Pablo Galindo 在 bpo-43823 中貢獻。)

  • 沒有 exceptfinally 區塊的 try 區塊:

    >>> try:
    ...     x = 2
    ... something = 3
      File "<stdin>", line 3
        something  = 3
        ^^^^^^^^^
    SyntaxError: expected 'except' or 'finally' block
    

    (由 Pablo Galindo 在 bpo-44305 中貢獻。)

  • 於比較中使用 = 而非 ==

    >>> if rocket.position = event_horizon:
      File "<stdin>", line 1
        if rocket.position = event_horizon:
                           ^
    SyntaxError: cannot assign to attribute here. Maybe you meant '==' instead of '='?
    

    (由 Pablo Galindo 在 bpo-43797 中貢獻。)

  • f 字串中使用 *

    >>> f"Black holes {*all_black_holes} and revelations"
      File "<stdin>", line 1
        (*all_black_holes)
         ^
    SyntaxError: f-string: cannot use starred expression here
    

    (由 Pablo Galindo 在 bpo-41064 中貢獻。)

IndentationErrors

許多 IndentationError 例外現在支援更多關於哪種區塊需要縮進的情境,包括陳述式的位置:

>>> def foo():
...    if lel:
...    x = 2
  File "<stdin>", line 3
    x = 2
    ^
IndentationError: expected an indented block after 'if' statement in line 2

AttributeErrors

當印出 AttributeError 時,PyErr_Display() 將提供引發例外的物件中類似屬性名稱的建議:

>>> collections.namedtoplo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'collections' has no attribute 'namedtoplo'. Did you mean: namedtuple?

(由 Pablo Galindo 在 bpo-38530 中貢獻。)

警告

請注意,如果未呼叫 PyErr_Display() 來顯示錯誤(可能為了要使用其他自定義錯誤顯示函式),則此操作將不起作用。這是 IPython 等某些 REPL 中的常見狀況。

NameErrors

當印出直譯器引發的 NameError 時,PyErr_Display() 將在引發例外的函式中提供類似變數名稱的建議:

>>> schwarzschild_black_hole = None
>>> schwarschild_black_hole
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'schwarschild_black_hole' is not defined. Did you mean: schwarzschild_black_hole?

(由 Pablo Galindo 在 bpo-38530 中貢獻。)

警告

請注意,如果未呼叫 PyErr_Display() 來顯示錯誤,則此操作將不起作用,如果使用其他自定義錯誤顯示函式,則可能會發生這種情況。這是 IPython 等某些 REPL 中的常見場景。

PEP 626:用於除錯和其他工具的精確列號

PEP 626 為除錯、分析 (profiling) 和覆蓋 (coverage) 工具帶來了更精確、更可靠的列號 (line numbers)。為所有已執行的程式碼列且僅針對已執行的程式碼行產生具有正確列號的追蹤事件。

帧对象的 f_lineno 属性将总是包含预期的行号。

代码对象 的的 co_lnotab 属性已被弃用并将在 3.12 中被移除。 需要从偏移量转换为行号的代码应当改用新的 co_lines() 方法。

PEP 634:結構模式匹配

已新增結構模式匹配 (structural pattern matching),其形式為具有關聯操作之模式的 match 陳述式case 陳述式。模式由序列、對映、原始資料型別 (primitive data types) 以及類別實例組成。模式匹配使程式能夠從複雜的資料型別中提取資訊,在資料結構上進行分支,並根據不同形式的資料應用特定的操作。

語法和操作

模式匹配的通用語法是:

match subject:
    case <pattern_1>:
        <action_1>
    case <pattern_2>:
        <action_2>
    case <pattern_3>:
        <action_3>
    case _:
        <action_wildcard>

match 陳述式採用一個運算式,並將其值與作為一個或多個 case 區塊給出的連續模式進行比較。具體來說,模式匹配是透過以下方式進行操作:

  1. 使用具有型態 (type) 和特徵 (shape) 的資料 (主語 subject)

  2. match 陳述式中 subject 的求值 (evaluating)

  3. 從上到下將主語與 case 陳述式中的每個模式進行比較,直到確認匹配。

  4. 執行與已確認匹配模式對應的操作

  5. 如果未確認完全匹配,則最後一種情況,即萬用字元 _ (如果有提供)將作為匹配到的情況。如未有任何匹配且不存在萬用字元的 case,則整個 match 區塊會是個無操作 (no-op)。

宣告式方法 (Declarative approach)

讀者可能會透過使用 C、Java 或 JavaScript(以及許多其他語言)中的 switch 陳述式將主語(資料物件)與字面值 (literal)(模式)進行匹配的簡單範例來了解模式匹配。 switch 語句通常用於將物件/運算式與包含字面值的 case 陳述式進行比較。

更強大的模式匹配範例可以在 Scala 和 Elixir 等語言中找到。對於結構模式匹配,該方法是「宣告式的 (declarative)」,並且明確地說明了資料匹配的條件(模式)。

雖然使用巢狀 "if" 陳述式的「命令式 (imperative)」指令系列可用於完成類似於結構模式匹配的操作,但它不如「聲明式 (declarative)」方法清晰。相反地,「聲明式」方法規定了匹配所需滿足的條件,並且因其明確表達模式而更具可讀性。雖然結構模式匹配可以用其最簡單的形式達成,將變數與 case 陳述式中的字面值進行比較,但它對 Python 的真正價值在於它對主語的型態和特徵的處理。

簡單模式:與字面值匹配

讓我們將此範例視為最簡單形式的模式匹配:一個值(主語)與多個文字(模式)匹配。在下面的範例中,status 是匹配陳述式的主語。這些模式是每個 case 陳述式,其中文字表示請求狀態程式碼。與案例相關的操作在匹配後執行:

def http_error(status):
    match status:
        case 400:
            return "Bad request"
        case 404:
            return "Not found"
        case 418:
            return "I'm a teapot"
        case _:
            return "Something's wrong with the internet"

如果上面的函式傳遞了 418 status,則回傳 "I'm a teapot"。如果上面的函式傳遞了 500 status,則帶有 _ 的 case 語句將作為萬用字元進行匹配,並回傳 "Something's wrong with the internet"。請注意最後一個區塊:變數名稱 _ 充當 萬用字元 並確保主語始終匹配。_ 的使用是可選的。

你可以使用 | ("or") 將多個字面值組合在一個模式中:

case 401 | 403 | 404:
    return "Not allowed"
沒有萬用字元 (wildcard) 的行為

如果我們透過刪除最後一個 case 區塊來修改上面的範例,則範例將變為:

def http_error(status):
    match status:
        case 400:
            return "Bad request"
        case 404:
            return "Not found"
        case 418:
            return "I'm a teapot"

如果在 case 陳述式中不使用 _,則可能不存在匹配項目。如果不存在匹配項目,則該行為是無操作 (no-op)。例如,如果 status 為 500,則不會有任何操作。

具有字面值和變數的模式

模式看起來就像解包賦值 (unpacking assignment),並且模式可用於繫結 (bind) 變數。在此範例中,可以將資料點解包為其 x 坐標和 y 坐標:

# point is an (x, y) tuple
match point:
    case (0, 0):
        print("Origin")
    case (0, y):
        print(f"Y={y}")
    case (x, 0):
        print(f"X={x}")
    case (x, y):
        print(f"X={x}, Y={y}")
    case _:
        raise ValueError("Not a point")

第一個模式有兩個字面值 (0, 0),並且可以被認為是上面顯示的字面值模式的擴充。接下來的兩個模式組合了一個字面值和一個變數,並且變數繫結來自主語(point)的值。第四個模式捕獲兩個值,這使得它在概念上類似於解包賦值 (x, y) = point

模式和類別

如果你使用類別來建構資料,則可以用類別名稱與後面的引數列表組合成的建構函式作為模式。該模式能夠將類別屬性捕獲到變數中:

class Point:
    x: int
    y: int

def location(point):
    match point:
        case Point(x=0, y=0):
            print("Origin is the point's location.")
        case Point(x=0, y=y):
            print(f"Y={y} and the point is on the y-axis.")
        case Point(x=x, y=0):
            print(f"X={x} and the point is on the x-axis.")
        case Point():
            print("The point is located somewhere else on the plane.")
        case _:
            print("Not a point")
具有位置參數的模式

你可以將位置參數與一些會為其屬性排序的內建類別(例如 dataclasses)一起使用。你還可以通過在類別中設定 __match_args__ 特殊屬性來定義模式中屬性的特定位置。如果它被設定為 ("x", "y"),則以下模式都是等效的(且都將 y 屬性繫結到 var 變數):

Point(1, var)
Point(1, y=var)
Point(x=1, y=var)
Point(y=var, x=1)

巢狀模式

模式可以任意巢套。例如,如果我們的資料是一個簡短的座標點列表,則可以這樣匹配:

match points:
    case []:
        print("No points in the list.")
    case [Point(0, 0)]:
        print("The origin is the only point in the list.")
    case [Point(x, y)]:
        print(f"A single point {x}, {y} is in the list.")
    case [Point(0, y1), Point(0, y2)]:
        print(f"Two points on the Y axis at {y1}, {y2} are in the list.")
    case _:
        print("Something else is found in the list.")

複雜模式和萬用字元

到目前為止,範例在最後一個 case 陳述式中單獨使用了 _。萬用字元可以用在更複雜的模式中,像是 ('error', code, _)。例如

match test_variable:
    case ('warning', code, 40):
        print("A warning has been received.")
    case ('error', code, _):
        print(f"An error {code} occurred.")

在上述情況下,值像是 ('error', code, 100) 和 ('error', code, 800) 的 test_variable 將會成功匹配。

Guard

我們可以在模式中新增一個 if 子句,稱為 "guard"。如果 guard 為 false,則 match 會繼續嘗試下一個 case 區塊。請注意,值的捕獲發生在 guard 的求值 (evaluate) 之前:

match point:
    case Point(x, y) if x == y:
        print(f"The point is located on the diagonal Y=X at {x}.")
    case Point(x, y):
        print(f"Point is not on the diagonal.")

其他主要功能

其他幾個主要功能:

  • 與賦值的解包一樣,tuple 和 list 模式具有完全相同的含義,並且實際上匹配任意序列。從技術上來說,主語必須是一個序列。因此,一個重要的例外是模式不會去匹配疊代器。另外,為了防止常常出錯,序列模式也不會去匹配字串。

  • 序列模式支援萬用字元:[x, y, *rest](x, y, *rest) 與解包賦值中的萬用字元類似。 * 後面的名稱也可能是 _,因此 (x, y, *_) 會匹配至少兩個項目的序列,且不繫結其餘項目。

  • 對映模式: {"bandwidth": b, "latency": l} 從字典中捕獲 "bandwidth""latency" 值。與序列模式不同,額外的鍵將被忽略。也支援萬用字元 **rest。(但是 **_ 是多餘的,所以是不允許的。)

  • 可以使用 as 關鍵字捕獲子模式:

    case (Point(x1, y1), Point(x2, y2) as p2): ...
    

    這將繫結 x1、y1、x2、y2,如同沒有 as 子句的情況下所預期的,並將 p2 繫結到主語的整個第二項目。

  • 大多數字面值都是通過相等進行比較的。然而,單例 TrueFalseNone 是按標識值 (identity) 來進行比較的。

  • 附名常數 (named constant) 可以在模式中使用。這些附名常數必須有帶有點的名稱 (dotted name),以防止常數被直譯為捕獲的變數:

    from enum import Enum
    class Color(Enum):
        RED = 0
        GREEN = 1
        BLUE = 2
    
    match color:
        case Color.RED:
            print("I see red!")
        case Color.GREEN:
            print("Grass is green")
        case Color.BLUE:
            print("I'm feeling the blues :(")
    

有關完整規範,請參閱 PEP 634。動機和基本原理位於 PEP 635 中,較完整的教學位於 PEP 636 中。

可選的 EncodingWarningencoding="locale" 選項

TextIOWrapperopen() 的預設編碼取決於平台和區域設定。由於大多數 Unix 平台都使用 UTF-8,因此在打開 UTF-8 檔案(例如 JSON、YAML、TOML、Markdown)時省略 encoding 選項是個常見的 bug,例如:

# BUG: "rb" mode or encoding="utf-8" should be used.
with open("data.json") as f:
    data = json.load(f)

為了發現這種錯誤,新增了一個可選的 EncodingWarning。當 sys.flags.warn_default_encoding 為 true 且使用特定於語言環境的預設編碼時,會發出該信號。

新增 -X warn_default_encoding 選項和 PYTHONWARNDEFAULTENCODING 來啟用警告。

更多資訊請見 文字編碼

其他語言變化

  • int 型別有一個新方法 int.bit_count(),回傳給定整數的二進位展開式中 1 的數量,也稱為總體計數 (population count)。(由 Niklas Fiekas 在 bpo-29882 中貢獻。)

  • dict.keys()dict.values()dict.items() 回傳的視圖 (view) 現在都有一個 mapping 屬性,該屬性提供 types.MappingProxyType 包裝原始的字典物件。(由 Dennis Sweeney 在 bpo-40890 中貢獻。)

  • PEP 618zip() 函式現在有一個可選的 strict 旗標,用於要求所有可疊代物件具有相同的長度。

  • 採用整數引數的內建函式和擴充函式不再接受 DecimalFraction 以及其他只能在有損失的情況下轉換為整數的物件(例如有 __int__() 方法,但沒有 __index__() 方法)。(由 Serhiy Storchaka 在 bpo-37999 中貢獻。)

  • 如果 object.__ipow__() 返回 NotImplemented,该运算符将按照预期正确地回退至 object.__pow__()object.__rpow__()。 (由 Alex Shkop 在 bpo-38302 中贡献。)

  • 現在可以在集合字面值 (set literals) 和集合綜合運算 (set comprehensions) 以及序列索引(但不能是切片)中使用不帶括號的賦值運算式 (assignment expressions)。

  • 函式有一個新的 __builtins__ 屬性,用於在執行函式時查找內建符號,而不是查找 __globals__['__builtins__'] 。如果 __globals__["__builtins__"] 存在,則屬性會以此做初始化,否則從當前內建物件 (builtins) 初始化。(由 Mark Shannon 在 bpo-42990 中貢獻。)

  • 新增兩個內建函式 -- aiter()anext(),分別為 iter()next() 提供非同步的對應函式。(由 Joshua Bronson、Daniel Pope 和 Justin Wang 在 bpo-31861 中貢獻。)

  • 靜態方法 (@staticmethod) 和類別方法 (@classmethod) 現在繼承方法屬性 (__module__, __name__, __qualname__, __doc__, __annotations__) 並有一個新的 __wrapped__ 屬性。此外,靜態方法現在可以像是常規函式般呼叫。(由 Victor Stinner 在 bpo-43682 中貢獻。)

  • 複雜目標(除 PEP 526 定義的 simple name 目標之外的所有內容)的註釋不再使用 from __future__ import comments 造成任何執行環境 (runtime) 影響。(由 Batuhan Taskaya 在 bpo-42737 中貢獻。)

  • 類別和模組物件現在會根據需求來延遲建立 (lazy-create) 空的註釋字典 (annotations dicts)。註釋字典存儲在物件的 __dict__ 中以達成向後相容性。這改進了 __annotations__ 使用方式的最佳實踐方法;有關更多資訊,請參閱 注解最佳实践。(由 Larry Hastings 在 bpo-43901 中貢獻。)

  • 附名運算式或由 yieldyield fromawait 組成的註釋現在在 from __future__ import comments 下被禁止,因為它們有些不預期的行為。(由 Batuhan Taskaya 在 bpo-42725 中貢獻。)

  • 未繫結變數 (unbound variable)、super() 和其他可能會改變處理註釋之符號表 (symbol table) 的運算式,現在在 from __future__ import comments 下變得無效。(由 Batuhan Taskaya 在 bpo-42725 中貢獻。)

  • float 型別和 decimal.Decimal 型別的 NaN 值的雜湊值現在取決於物件的標識值 (identity)。以前即使 NaN 值彼此不相等,它們也總是被雜湊為 0。由於在建立包含多個 NaN 的字典和集合時出現過多的雜湊衝突 (hash collision),可能導致潛在的二次方執行環境行為 (quadratic runtime behavior)。(由 Raymond Hettinger 在 bpo-43475 中貢獻。)

  • 当删除 __debug__ 常量时将引发 SyntaxError (而不是 NameError)。 (由 Donghee Na 在 bpo-45000 中贡献。)

  • SyntaxError 例外現在具有 end_linenoend_offset 屬性。如果未被決定,它們將會是 None。(由 Pablo Galindo 在 bpo-43914 中貢獻。)

新模組

  • 无。

改進的模組

asyncio

新增缺少的 connect_accepted_socket() 方法。(由 Alex Grönholm 在 bpo-41332 中貢獻。)

argparse

argparse 幫助中的誤導性用詞「可選引數 (optional arguments)」已被替換為「選項 (options)」。某些依賴於精確輸出匹配的測試可能需要進行調整。(由 Raymond Hettinger 在 bpo-9694 中貢獻。)

array

array.arrayindex() 方法現在具有可選的 startstop 參數。(由 Anders Lorentsen 和 Zackery Spytz 在 bpo-31956 中貢獻。)

asynchat, asyncore, smtpd

自 Python 3.6 起,這些模組在其文件中被標記為已棄用。引入時的 DeprecationWarning 現已新增到這三個模組中。

base64

新增 base64.b32hexencode()base64.b32hexdecode() 以支援擴充十六進位字母的 Base32 編碼 (Base32 Encoding with Extended Hex Alphabet)。

bdb

新增 clearBreakpoints() 來重置所有設定的斷點。(由 Irit Katriel 在 bpo-24160 中貢獻。)

bisect

新增向 bisect 模組 API 提供 key 函式的可能性。(由 Raymond Hettinger 在 bpo-4356 中貢獻。)

codecs

新增 codecs.unregister() 函式來取消註冊 (unregister) 一個編解碼器的搜索功能。 (Hai Shi在 bpo-41842 中貢獻。)

collections.abc

collections.abc.Callable參數化泛型 (parameterized generic)__args__ 現在與 typing.Callable 一致。collections.abc.Callable 泛型現在會將型別參數攤平,類似於 typing.Callable 目前的做法。這意味著 collections.abc.Callable[[int, str], str] 將具有 (int, str, str)__args__;在以前這是 ([int, str], str)。為了允許此更改,現在可以對 types.GenericAlias 進行子類別化,並且在下標 (subscript) collections.abc.Callable 型別時將回傳子類別。請注意,對於無效形式的 collections.abc.Callable 參數化可能會引發 TypeError,而在 Python 3.9 中該參數可能會無引發例外地傳遞。(由 Ken Jin 在 bpo-42195 中貢獻。)

contextlib

新增 contextlib.aclosing() 情境管理器以安全地關閉非同步產生器和表示非同步釋放資源的物件。(由 Joongi Kim 和 John Belmonte 在 bpo-41229 中貢獻。)

contextlib.nullcontext() 新增非同步情境管理器支援。(由 Tom Gringauz 在 bpo-41543 中貢獻。)

新增 AsyncContextDecorator,用於支援將非同步情境管理器作為裝飾器使用。

curses

ncurses 6.1 中新增的擴充顏色函式將由 curses.color_content()curses.init_color()curses.init_pair()curses.pair_content() 透明地使用。新函式 curses.has_extended_color_support() 表示了底層的 ncurses 函式庫是否支援擴充顏色。 (由 Jeffrey Kintscher 和 Hans Petter Jansson 在 bpo-36982 中貢獻。)

如果 BUTTON5_* 常數是由底層 curses 函式庫提供的,那麼它們現在會在 curses 模組中公開。(由 Zackery Spytz 在 bpo-39273 中貢獻。)

dataclasses

__slots__

dataclasses.dataclass() 裝飾器中新增了 slots 參數。(由 Yurii Karabas 在 bpo-42269 中貢獻)

僅限關鍵字欄位 (Keyword-only fields)

dataclasses 現在支援在產生的 __init__ 方法中包含僅限關鍵字的欄位。有多種方法可以指定僅限關鍵字欄位。

你可以說每個欄位都是關鍵字:

from dataclasses import dataclass

@dataclass(kw_only=True)
class Birthday:
    name: str
    birthday: datetime.date

namebirthday 都是產生的 __init__ 方法的僅限關鍵字參數。

你可以在每個欄位的基礎上指定僅限關鍵字:

from dataclasses import dataclass, field

@dataclass
class Birthday:
    name: str
    birthday: datetime.date = field(kw_only=True)

這裡只有 birthday 是僅限關鍵字。如果你在各個欄位上設定 kw_only,請注意,由於僅限關鍵字欄位需要遵循非僅限關鍵字欄位,因此會有欄位重新排序的相關規則。詳細資訊請參閱完整的 dataclasses 文件。

你還可以指定 KW_ONLY 標記後面的所有欄位均為僅限關鍵字欄位。這可能是最常見的用法:

from dataclasses import dataclass, KW_ONLY

@dataclass
class Point:
    x: float
    y: float
    _: KW_ONLY
    z: float = 0.0
    t: float = 0.0

這裡的 zt 是僅限關鍵字參數,而 xy 則不是。(由 Eric V. Smith 在 bpo-43532 中貢獻。)

distutils

整個 distutils 套件已被棄用,將在 Python 3.12 中刪除。它指定套件建置的功能已經完全被第三方套件 setuptoolspackaging 所取代,並且大多數其他常用的 API 都可以在標準函式庫的其他地方被找到(例如 platformshutilsubprocesssysconfig)。目前沒有將 distutils 遷移任何其他地方的計畫,且使用其他功能的應用程式應該開始規劃如何取得程式碼的私有副本。請參閱 PEP 632 的討論。

Python 3.8 中不推薦使用的 bdist_wininst 命令已被刪除。現在建議使用 bdist_wheel 命令來在 Windows 上發布二進位套件。(由 Victor Stinner 在 bpo-42802 中貢獻。)

doctest

當模組未定義 __loader__ 時,回退到 __spec__.loader 。(由 Brett Cannon 在 bpo-42133 中貢獻。)

encodings

encodings.normalize_encoding() 現在會忽略非 ASCII 字元。(Hai Shi 在 bpo-39337 中貢獻。)

enum

Enum __repr__() 現在會回傳 enum_name.member_name__str__() 現在會回傳 member_name 。可用作模組常數的標準函式庫列舉會有 module_name.member_namerepr()。(由 Ethan Furman 在 bpo-40066 中貢獻。)

新增 enum.StrEnum,為所有成員都是字串的列舉。(由 Ethan Furman 在 bpo-41816 中貢獻。)

fileinput

fileinput.input()fileinput.FileInput 中新增 encodingerrors 參數。(由 Inada Naoki 在 bpo-43712 中貢獻。)

mode 為 "r" 並且檔案有被壓縮時,fileinput.hook_compressed() 現在會回傳 TextIOWrapper 物件(和未壓縮檔案一樣)。(由 Inada Naoki 在 bpo-5758 中貢獻。)

faulthandler

faulthandler 模組現在可以檢測垃圾收集器 (garbage collector) 在收集期間是否發生嚴重錯誤。(由 Victor Stinner 在 bpo-44466 中貢獻。)

gc

gc.get_objects()gc.get_referrers()gc.get_referents() 新增稽核掛鉤 (audit hooks)。(由 Pablo Galindo 在 bpo-43439 中貢獻。)

glob

glob()iglob() 中新增 root_dirdir_fd 參數,允許指定搜索的根目錄。(由 Serhiy Storchaka 在 bpo-38144 中貢獻。)

hashlib

hashlib 模組需要 OpenSSL 1.1.1 或更高版本。(由 Christian Heimes 在 PEP 644bpo-43669 中貢獻。)

hashlib 模組初步支援 OpenSSL 3.0.0。(由 Christian Heimes 在 bpo-38820 和其他問題中貢獻。)

純 Python 的 pbkdf2_hmac() 回退已被棄用。將來只有在有 OpenSSL 支援的建置 Python 中才能夠使用 PBKDF2-HMAC。(由 Christian Heimes 在 bpo-43880 中貢獻。)

hmac

hmac 模組現在在內部使用 OpenSSL 的 HMAC 實作。 (由 Christian Heimes 在 bpo-40645 中貢獻。)

IDLE 和 idlelib

讓 IDLE 調用 sys.excepthook() (在沒有 -n 的情況下啟動時)。使用者掛鉤 (user hooks) 在以前是被忽略的。(由 Ken Hilton 在 bpo-43008 中貢獻。)

重新排列設定對話框。將 General 分頁拆分為 Windows 和 Shell/Ed 分頁。將擴充 Help 選單的幫助來源移至 Extensions 分頁。為新選項騰出空間並縮短對話框,而後者使對話框更好地適應較小的螢幕。(由 Terry Jan Reedy 在 bpo-40468 中貢獻。)將縮排空間設定從 Font 分頁移至新的 Windows 分頁。(由 Mark Roseman 和 Terry Jan Reedy 在 bpo-33962 中貢獻。)

上述更改已向後移植到 3.9 維護版本。

新增 Shell 側邊欄。將主要提示字元 (>>>) 移至側邊欄。將輔助提示字元(...)新增到側邊欄。點擊左鍵再拖動能夠選擇一行或多行文字,和編輯器列號側邊欄操作一樣。選擇文字列後點擊右鍵會顯示帶有「一併複製提示字元 (copy with prompts)」的情境選單,這會將側邊欄中提示字元與所選文字並排,此選項也會出現在文字的情境選單上。(由 Tal Einat 在 bpo-37903 中貢獻。)

使用空格而不是製表符號 (tab) 來縮進交互式程式碼。這能夠使交互式程式碼條目「看起來正確」。新增 shell 側邊欄的主要動機是實現這一點。(由 Terry Jan Reedy 在 bpo-37892 中貢獻。)

突顯 (highlight) 模式匹配陳述式中的新軟關鍵字 (soft keywords) matchcase_。然而這種突顯並不完美,並且在某些罕見的情況下會出錯,包括 case 模式中的一些 _。(由 Tal Einat 在 bpo-44010 中貢獻。)

3.10 維護版本中的新增功能。

將語法突顯 (syntax highlighting) 應用於 .pyi 檔案。(由 Alex Waygood 和 Terry Jan Reedy 在 bpo-45447 中貢獻。)

保存帶有輸入和輸出的 Shell 時,會包含提示字元。(由 Terry Jan Reedy 在 gh-95191 中貢獻。)

importlib.metadata

importlib_metadata 4.6 功能相同(歷史)。

importlib.metadata 入口點現在透過新的 importlib.metadata.EntryPoints 類別提供了以群組和名稱選擇入口點的更好體驗。有關棄用與用法的更多資訊,請參閱文件中的相容性說明。

新增了 importlib.metadata.packages_distributions() 用於將頂階 Python 模組和套件解析出 importlib.metadata.Distribution

inspect

當模組未定義 __loader__ 時,回退到 __spec__.loader 。(由 Brett Cannon 在 bpo-42133 中貢獻。)

新增 inspect.get_annotations(),它可以安全地計算物件上定義的註釋。它是存取各種型別物件註釋的怪作法 (quirks) 的變通解法 (work around),並且對其檢查的物件做出很少的假設。 inspect.get_annotations() 也可以正確地取消字串化註釋 (stringized annotations)。 inspect.get_annotations() 現在被認為是存取任何 Python 物件上定義的註釋字典的最佳實踐;有關使用註釋的最佳實踐的更多資訊,請參閱 注解最佳实践。相關地,inspect.signature()inspect.Signature.from_callable()inspect.Signature.from_function() 現在呼叫 inspect.get_annotations() 來檢索註釋。這意味著 inspect.signature()inspect.Signature.from_callable() 現在也可以取消字串化註釋。(由 Larry Hastings 在 bpo-43817 中貢獻。)

itertools

新增 itertools.pairwise()。(由 Raymond Hettinger 在 bpo-38200 中貢獻。)

linecache

當模組未定義 __loader__ 時,回退到 __spec__.loader 。(由 Brett Cannon 在 bpo-42133 中貢獻。)

os

為 VxWorks RTOS 新增 os.cpu_count() 支援。(由 Peixing Xin 在 bpo-41440 中貢獻。)

新增函式 os.eventfd() 和相關幫助程式來包裝 Linux 上的 eventfd2 系統呼叫。 (由 Christian Heimes 在 bpo-41001 中貢獻。)

新增 os.splice() 以允許在兩個檔案描述器 (file descriptor) 之間移動資料,而無需在核心地址空間 (kernel address space) 和使用者地址空間 (user address space) 之間進行複製,其中檔案描述器之一必須是個 pipe。(由 Pablo Galindo 在 bpo-41625 中貢獻。)

为 macOS 增加了 O_EVTONLY, O_FSYNC, O_SYMLINKO_NOFOLLOW_ANY。 (由 Donghee Na 在 bpo-43106 中贡献。)

os.path

os.path.realpath() 現在接受一個 strict 僅限關鍵字引數。當設定為 True 時,如果路徑不存在或遇到符號鏈接循環 (symlink loop),則會引發 OSError。(由 Barney Gale 在 bpo-43757 中貢獻。)

pathlib

新增 PurePath.parents 對於切片的支援。 (由 Joshua Cannon 在 bpo-35498 中貢獻。)

PurePath.parents 新增負索引支援。(由 Yaroslav Pankovych 在 bpo-21041 中貢獻。)

新增替代 link_to()Path.hardlink_to 方法。新方法與 symlink_to() 具有相同的引數順序。(由 Barney Gale 在 bpo-39950 中貢獻。)

pathlib.Path.stat()chmod() 現在接受 follow_symlinks 僅限關鍵字引數,以與 os 模組中的相應函式保持一致。(由 Barney Gale 在 bpo-39906 中貢獻。)

platform

新增 platform.freedesktop_os_release() 以從 freedesktop.org os-release 標準檔案中檢索出作業系統標識。 (由 Christian Heimes 在 bpo-28468 中貢獻。)

pprint

pprint.pprint() 現在接受新的 underscore_numbers 關鍵字引數。(由 sblondon 在 bpo-42914 中貢獻。)

pprint 現在可以漂亮地印出 dataclasses.dataclass 實例。(由 Lewis Gaul 在 bpo-43080 中貢獻。)

py_compile

--quiet 選項新增到 py_compile 的命令列界面。(由 Gregory Schevchenko 在 bpo-38731 中貢獻。)

pyclbr

pyclbr.readmodule()pyclbr.readmodule_ex() 返回的结果树中的 FunctionClass 对象上添加一个 end_lineno 属性。 它将匹配现有的 (起始) lineno。 (由 Aviral Srivastava 在 bpo-38307 中贡献。)

shelve

现在 shelve 在创建 shelve 时默认使用 pickle.DEFAULT_PROTOCOL 而不是 pickle 协议 3。 (由 Zackery Spytz 在 bpo-34204 中贡献。)

statistics

新增 covariance()、Pearson correlation() 和簡單 linear_regression() 函式。(由 Tymoteusz Wołodźko 在 bpo-38490 中貢獻。)

site

當模組未定義 __loader__ 時,回退到 __spec__.loader 。(由 Brett Cannon 在 bpo-42133 中貢獻。)

socket

socket.timeout 例外現在是 TimeoutError 的別名。(由 Christian Heimes 在 bpo-42413 中貢獻。)

新增使用 IPPROTO_MPTCP 建立 MPTCP socket 的選項(由 Rui Cunha 在 bpo-43571 中貢獻。)

新增 IP_RECVTOS 選項以接收服務型別 (type of service, ToS) 或 DSCP/ECN 欄位(由 Georg Sauthoff 在 44077 中貢獻。)

ssl

ssl 模組需要 OpenSSL 1.1.1 或更高版本。(由 Christian Heimes 在 PEP 644bpo-43669 中貢獻。)

ssl 模块已初步支持 OpenSSL 3.0.0 和新选项 OP_IGNORE_UNEXPECTED_EOF。 (由 Christian Heimes 在 bpo-38820, bpo-43794, bpo-43788, bpo-43791, bpo-43799, bpo-43920, bpo-43789bpo-43811 中贡献。)

已棄用函式和使用已棄用常數現在會導致 DeprecationWarningssl.SSLContext.options 預設設定有 OP_NO_SSLv2OP_NO_SSLv3,因此無法再次發出設定該旗標的警告。棄用部分包含已棄用功能的列表。(由 Christian Heimes 在 bpo-43880 中貢獻。)

ssl 模組現在具有更安全的預設設定。預設情況下禁用沒有前向保密或 SHA-1 MAC 的密碼。安全級別 2 禁止安全性低於 112 位元的弱 RSA、DH 和 ECC 密鑰。 SSLContext 預設為最低協議版本 TLS 1.2。設定基於 Hynek Schlawack 的研究。 (由 Christian Heimes 在 bpo-43998 中貢獻。)

不再正式支援已棄用的協議 SSL 3.0、TLS 1.0 和 TLS 1.1。 Python 不會主動阻止它們。然而,OpenSSL 建置選項、發行版配置、發行商補丁和密碼套件可能會阻止交握的成功。

ssl.get_server_certificate() 函式新增 timeout 參數。(由 Zackery Spytz 在 bpo-31870 中貢獻。)

ssl 模組使用堆疊類型 (heap-types) 和多階段初始化 (multi-phase initialization)。(由 Christian Heimes 在 bpo-42333 中貢獻。)

增加了一个新的校验旗标 VERIFY_X509_PARTIAL_CHAIN。 (由 l0x 在 bpo-40849 中贡献。)

sqlite3

新增 connect/handle()enable_load_extension()load_extension() 的稽核事件。(由 Erlend E. Aasland 在 bpo-43762 中貢獻。)

sys

新增 sys.orig_argv 屬性:傳遞給 Python 可執行檔案的原始命令列引數列表。(由 Victor Stinner 在 bpo-23427 中貢獻。)

新增 sys.stdlib_module_names,其中包含標準函式庫模組的名稱列表。 (由 Victor Stinner 在 bpo-42955 中貢獻。)

_thread

现在 _thread.interrupt_main() 接受一个可选的信号数值供模拟 (默认值仍为 signal.SIGINT)。 (由 Antoine Pitrou 在 bpo-43356 中贡献。)

threading

新增 threading.gettrace()threading.getprofile() 分別取得 threading.settrace()threading.setprofile() 設定的函式。(由 Mario Corchero 在 bpo-42251 中貢獻。)

新增 threading.__excepthook__ 以允許取得 threading.excepthook() 的原始值,以防它被設定為損壞或不同的值。(由 Mario Corchero 在 bpo-42308 中貢獻。)

traceback

format_exception()format_exception_only()print_exception() 函式現在可以將例外物件作為僅限位置引數。(由 Zackery Spytz 和 Matthias Bussonnier 在 bpo-26389 中貢獻。)

types

重新引入 types.EllipsisTypetypes.NoneTypetypes.NotImplementedType 類別,提供一組易於型別檢查器直譯的新型別。(由 Bas van Beek 在 bpo-41810 中貢獻。)

typing

有關重大更改,請參閱與型別提示相關的新功能

typing.Literal 的行為已更改為符合 PEP 586 並匹配 PEP 中指定的靜態型別檢查器的行為。

  1. Literal 現在可以刪除重複參數。

  2. Literal 物件之間的相等性比較現在與順序無關。

  3. 現在型別的比較會優先於 Literal 的比較。例如,Literal[0] == Literal[False] 先前之求值為 True,但現在它是 False。為了支援此更改,內部使用的型別快取現在支援了型別的辨認。

  4. 如果 Literal 物件的任ㄧ參數不是可雜湊的,那麼它們現在將在相等性比較期間引發 TypeError 例外。請注意,使用不可雜湊的參數宣告 Literal 不會引發錯誤:

    >>> from typing import Literal
    >>> Literal[{0}]
    >>> Literal[{0}] == Literal[{False}]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unhashable type: 'set'
    

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

新增函式 typing.is_typeddict() 來自我審查 (introspect) 註釋是否為 typing.TypedDict。(由 Patrick Reader 在 bpo-41792 中貢獻。)

僅宣告了資料變數的 typing.Protocol 子類別現在在使用 isinstance 檢查時會引發 TypeError ,除非它們用 runtime_checkable() 裝飾。此前,這些檢查都是悄無聲息地通過的。如果使用者需要執行環境協議 (runtime protocol),則應該使用 runtime_checkable() 裝飾器來裝飾其子類別。(由 Yurii Karabas 在 bpo-38908 中貢獻。)

typing.iotyping.re 子模組引入現在將發出 DeprecationWarning。這些子模組自 Python 3.8 起已被棄用,並將在未來版本的 Python 中刪除。屬於這些子模組的任何內容都應該直接從 typing 引入。 (由 Sebastian Rittau 在 bpo-38291 中貢獻。)

unittest

新增方法 assertNoLogs() 以補足現有的 assertLogs()。(由 Kit Yan Choi 在 bpo-39385 中貢獻。)

urllib.parse

Python 3.10 之前的 Python 版本允許在 urllib.parse.parse_qs()urllib.parse.parse_qsl() 中使用 ;& 作為查詢參數 (query parameter) 的分隔符號。出於安全考慮,並且為了符合更新的 W3C 建議,已將其更改為僅允許單個分隔符號鍵,預設為 &。此更改還會影響 cgi.parse()cgi.parse_multipart(),因為它們在內部使用受影響的函式。有關更多詳細資訊,請參閱各自的文件。(由 Adam Goldschmidt、Senthil Kumaran 和 Ken Jin 在 bpo-42967 中貢獻。)

在 URL 中存在换行符或制表符可能会导致某种形式的攻击。 根据更新了 RFC 3986 的 WHATWG 规范,urllib.parse 中的解析器将从 URL 中去除 ASCII 换行符 \n, \r 和制表符 \t 以防止这种攻击。 移除的字符将由一个新的模块层级变量 urllib.parse._UNSAFE_URL_BYTES_TO_REMOVE 来控制。 (参见 gh-88048。)

xml

新增 LexicalHandler 類別到 xml.sax.handler 模組。(由 Jonathan Gossage 和 Zackery Spytz 在 bpo-35018 中貢獻。)

zipimport

新增與 PEP 451 相關的方法:find_spec()zipimport.zipimporter.create_module()zipimport.zipimporter.exec_module()。(由 Brett Cannon 在 bpo-42131 中貢獻。)

新增 invalidate_caches() 方法。(由 Desmond Cheong 在 bpo-14678 中貢獻。)

最佳化

  • 建構函式 str()bytes()bytearray() 現在更快了(對於小型物件大約快了 30--40%)。(由 Serhiy Storchaka 在 bpo-41334 中貢獻。)

  • runpy 模組現在引入更少的模組。python3 -m module-name 指令啟動時間平均快了 1.4 倍。在 Linux 上,python3 -I -m module-name 在 Python 3.9 上引入 69 個模組,而在 Python 3.10 上僅引入 51 個模組 (-18)。(由 Victor Stinner 在 bpo-41006bpo-41718 中貢獻。)

  • LOAD_ATTR 指令現在使用新的「操作碼快取 (per opcode cache)」機制。現在一般屬性的速度提高了約 36%,槽位 (slot) 的速度提高了 44%。(由 Pablo Galindo 和 Yury Selivanov 在 bpo-42093 中以及 Guido van Rossum 在 bpo-42927 中貢獻,基於最初在 PyPy 和 MicroPython 中實作的想法。)

  • 當使用 --enable-optimizations 建置 Python 時,現在 -fno-semantic-interposition 被新增到編譯和鏈接列 (link line) 中。這使得使用 --enable-sharedgcc 建立的 Python 直譯器的建置速度提高了 30%。請參閱本文 以了解詳情。(由 Victor Stinner 和 Pablo Galindo 在 bpo-38980 中貢獻。)

  • bz2 / lzma / zlib 模組使用新的輸出緩衝區管理程式碼,並將 .readall() 函式新增到 _compression.DecompressReader 類別。 bz2 解壓縮速度提高了 1.09x ~ 1.17x,lzma 解壓縮速度提高了 1.20x ~ 1.32x,GzipFile.read(-1) 速度提高了 1.11x ~ 1.18x。(由 Ma Lin 於 bpo-41486 貢獻、由 Gregory P. Smith 審閱)

  • 使用字串化註釋時,建立函式時不再建立函式的註釋字典。取而代之的是它們被存儲為字串元組,且函式物件會根據需求才將其延遲轉換 (lazily convert) 為註釋字典。此最佳化將定義帶有註釋的函式所需的 CPU 時間減少了一半。(由 Yurii Karabas 和 Inada Naoki 在 bpo-42202 中貢獻。)

  • 像是 str1 in str2str2.find(str1) 之類的子字串搜索函式現在有時會使用 Crochemore & Perrin 的「雙向」字串搜索演算法來避免作用於長字串上時發生二次方行為 (quadratic behavior)。(由 Dennis Sweeney 在 bpo-41972 中貢獻)

  • _PyType_Lookup() 新增微最佳化以提高快取命中的常見情況下的型別屬性快取查找性能。這使得直譯器平均速度提高了 1.04 倍。(由 Dino Viehland 在 bpo-43452 中貢獻。)

  • 下列内置函数现在支持更快速的 PEP 590 vectorcall 调用约定: map(), filter(), reversed(), bool()float()。 (由 Donghee Na 和 Jeroen Demeyer 在 bpo-43575, bpo-43287, bpo-41922, bpo-41873bpo-41870 中贡献。)

  • 通過刪除內部 RLockBZ2File 的性能得到了改進。這使得 BZ2File 在面對多個同時的讀取器或寫入器時執行緒不安全,就像 gziplzma 中的等效類別一樣。(由 Inada Naoki 在 bpo-43785 中貢獻。)

已棄用

已刪除

  • 刪除了 complex 類別的特殊方法 __int____float____floordiv____mod____divmod____rfloordiv____rmod____rdivmod__ 。它們都會引發 TypeError。(由 Serhiy Storchaka 在 bpo-41974 中貢獻。)

  • _markupbase 模組中私有、未於文件記錄的 ParserBase.error() 方法已被刪除。html.parser.HTMLParserParserBase 的唯一子類別,它的 error() 實作已在 Python 3.5 中刪除。(由 Berker Peksag 在 bpo-31844 中貢獻。)

  • 刪除了 unicodedata.ucnhash_CAPI 屬性,該屬性是內部 PyCapsule 物件。相關的私有 _PyUnicode_Name_CAPI 結構已移至內部 C API。(由 Victor Stinner 在 bpo-42157 中貢獻。)

  • 刪除了由於切換到新的 PEG 剖析器而在 3.9 中被棄用的 parser 模組。僅由舊剖析器使用的所有 C 原始碼和標頭檔也已被刪除,包括 node.hparser.hgraminit.hgrammar.h

  • 刪除了公開 C API 函式 PyParser_SimpleParseStringFlagsPyParser_SimpleParseStringFlagsFilenamePyParser_SimpleParseFileFlagsPyNode_Compile,這些函式由於切換到新的 PEG 剖析器而在 3.9 中被棄用。

  • 移除了 formatter 模块,它在 Python 3.4 中已被弃用。 它相当过时、极少被使用,并且未经测试。 它最初计划在 Python 3.6 中移除,但此移除被延迟到 Python 2.7 生命期结束之后。 现有用户应当将它们用到的所有类都拷贝到自己的代码中。 (由 Donghee Na 和 Terry J. Reedy 在 bpo-42299 中贡献。)

  • 移除了 PyModule_GetWarningsModule() 函数,现在被由于 _warnings 模块在 2.6 中被转换为内置模块而变得没有用处。 (由 Hai Shi 在 bpo-42599 中贡献。)

  • collections 模組中刪除已棄用的、對 容器抽象基类 的別名。(由 Victor Stinner 在 bpo-37324 中貢獻。)

  • 在 Python 3.8 中棄用後,loop 參數已從大多數 asyncio高階 API 中刪除。這一變化的背後動機是多方面的:

    1. 這簡化了高階 API。

    2. 自 Python 3.7 以來,高階 API 中的函式一直隱式獲取當前執行緒正在運行的事件循環。在大多數正常用例中,不需要將事件循環傳遞給 API。

    3. 事件循環的傳遞很容易出錯,尤其是在處理在不同執行緒中運行的循環時。

    請注意,低階 API 仍會接受 loop。有關如何替換現有程式碼的範例,請參閱 Python API 的變化

    (由 Yurii Karabas、Andrew Svetlov、Yury Selivanov 和 Kyle Stanley 在 bpo-42392 中貢獻。)

移植到 Python 3.10

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

Python 語法的變化

  • 如果數字字面值後面緊跟關鍵字(如 0in x),在以前是有效的語法,但現在在編譯時會發出棄用警告。在未來的版本中,它將更改為語法警告,最後更改為語法錯誤。要消除警告並使程式碼與未來版本相容,只需在數字字面值和以下關鍵字之間新增一個空格即可。(由 Serhiy Storchaka 在 bpo-43833 中貢獻。)

Python API 的變化

  • format_exception()format_exception_only()traceback 模組中的 print_exception() 函式的 etype 參數已重命名為 exc。(由 Zackery Spytz 和 Matthias Bussonnier 在 bpo-26389 中貢獻。)

  • atexit:在 Python 退出時,如果一個使用 atexit.register() 註冊的回呼 (callback) 失敗,該例外現在會被記錄下來。在以前只記錄一些例外,並且最後一個例外總是被默默地忽略。(由 Victor Stinner 在 bpo-42639 中貢獻。)

  • collections.abc.Callable 泛型現在會攤平型別參數,類似於 typing.Callable 目前的做法。這意味著 collections.abc.Callable[[int, str], str] 將具有 (int, str, str)__args__;以前這是 ([int, str], str)。透過 typing.get_args()__args__ 存取參數的程式碼需要考慮此變更。此外,對於無效形式的參數化 collections.abc.Callable,可能會引發 TypeError,而在 Python 3.9 中,該參數可能已被默默地傳遞。(由 Ken Jin 在 bpo-42195 中貢獻。)

  • 如果給定參數不適合 16 位元無符號整數 (16-bit unsigned integer),socket.htons()socket.ntohs() 現在會引發 OverflowError 而不是 DeprecationWarning。(由 Erlend E. Aasland 在 bpo-42393 中貢獻。)

  • 在 Python 3.8 中棄用後,loop 參數已從大多數 asyncio高階 API 中刪除。

    目前如下所示的協程:

    async def foo(loop):
        await asyncio.sleep(1, loop=loop)
    

    應替換為:

    async def foo():
        await asyncio.sleep(1)
    

    如果 foo() 被專門設計為 在當前執行緒的事件循環中運行(例如在另一個執行緒的事件循環中運行),請考慮改用 asyncio.run_coroutine_threadsafe()

    (由 Yurii Karabas、Andrew Svetlov、Yury Selivanov 和 Kyle Stanley 在 bpo-42392 中貢獻。)

  • 如果 globals 字典沒有 "__builtins__" 鍵,則 types.FunctionType 建構函式現在會繼承當前的內建物件,而不是使用 {"None": None}:相同行為如 eval()exec() 函式。在 Python 中使用 def function(...): ... 定義函式不受影響,全域變數不能用此語法覆蓋:它也繼承當前的內建物件。 (由 Victor Stinner 在 bpo-42990 中貢獻。)

C API 中的改動

  • 由於切換到新的 PEG 剖析器,C API 函式 PyParser_SimpleParseStringFlagsPyParser_SimpleParseStringFlagsFilenamePyParser_SimpleParseFileFlagsPyNode_Compile 和被這些函式使用的型別 struct _node 被刪除。

    現在應該將源程式碼直接(例如透過 Py_CompileString())編譯為程式碼物件。然後可以(例如透過 PyEval_EvalCode())為產生的程式碼物件求值 (evaluated)。

    具體來說:

    • 後跟有 PyNode_Compile 呼叫的 PyParser_SimpleParseStringFlags 呼叫,可以替換為呼叫 Py_CompileString()

    • 沒有 PyParser_SimpleParseFileFlags 的直接替代品。要從 FILE * 引數編譯程式碼,你需要用 C 讀取檔案並將結果緩衝區傳遞給 Py_CompileString()

    • 要編譯給定 char * 檔案名稱的檔案,請顯式打開該檔案,讀取它並編譯結果。一種方法是使用 io 模組和 PyImport_ImportModule()PyObject_CallMethod()PyBytes_AsString()Py_CompileString(),如下所示。(宣告和錯誤處理在此被省略。):

      io_module = Import_ImportModule("io");
      fileobject = PyObject_CallMethod(io_module, "open", "ss", filename, "rb");
      source_bytes_object = PyObject_CallMethod(fileobject, "read", "");
      result = PyObject_CallMethod(fileobject, "close", "");
      source_buf = PyBytes_AsString(source_bytes_object);
      code = Py_CompileString(source_buf, filename, Py_file_input);
      
    • 对于 FrameObject 对象,f_lasti 成员现在代表一个字代码偏移而不是相对字节码字符串的简单偏移。 这意味着此数字需要乘以 2 才能被用于预期接受字节偏移的 API (例如 PyCode_Addr2Line())。 还要注意 FrameObject 对象的 f_lasti 成员已不被认为是稳定的:请改用 PyFrame_GetLineNumber()

CPython 位元組碼更改

  • MAKE_FUNCTION 指令現在接受字典或字串元組作為函式的註釋。(由 Yurii Karabas 和 Inada Naoki 在 bpo-42202 中貢獻。)

建置變更

  • PEP 644:Python 現在需要 OpenSSL 1.1.1 或更高版本。不再支援 OpenSSL 1.0.2。(由 Christian Heimes 在 bpo-43669 中貢獻。)

  • 現在需要 C99 函式 snprintf()vsnprintf() 來建置 Python。 (由 Victor Stinner 在 bpo-36020 中貢獻。)

  • sqlite3 需要 SQLite 3.7.15 或更新版本。(由 Sergey Fedoseev 和 Erlend E. Aasland 在 bpo-40744bpo-40810 中貢獻。)

  • atexit 模組現在必須都被建置為內建模組。(由 Victor Stinner 在 bpo-42639 中貢獻。)

  • --disable-test-modules 選項新增到 configure 腳本中:不建置也不安裝測試模組。(由 Xavier de Gaye、Thomas Petazzoni 和 Peixing Xin 在 bpo-27640 中貢獻。)

  • --with-wheel-pkg-dir=PATH 選項 新增到 ./configure 腳本中。如果有指定,ensurepip 模組會在此目錄中查找 setuptoolspip wheel 套件:如果兩者都存在,則使用這些 wheel 套件而不是 ensurepip 捆綁的 wheel 套件。

    一些 Linux 發行版的打包策略建議不要一併包入依賴項目。例如,Fedora 在 /usr/share/python-wheels/ 目錄中安裝 wheel 套件,並且不安裝 ensurepip._bundled 套件。

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

  • 新增 configure --without-static-libpython 選項 以不建置 libpythonMAJOR.MINOR.a 靜態函式庫且不安裝 python.o 目標檔案。

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

  • 如果可用,configure 腳本現在使用 pkg-config 工具程式 (utility) 來檢測 Tcl/Tk 標頭檔和函式庫的位置。和以前一樣,可以使用 --with-tcltk-includes--with-tcltk-libs 配置選項顯式指定這些位置。(由 Manolis Stamatogiannakis 在 bpo-42603 中貢獻。)

  • --with-openssl-rpath 選項新增到 configure 腳本中。該選項簡化了使用自定義 OpenSSL 安裝建置 Python 的過程,例如 ./configure --with-openssl=/path/to/openssl --with-openssl-rpath=auto。(由 Christian Heimes 在 bpo-43466 中貢獻。)

C API 變更

PEP 652:維護穩定 ABI

用於擴充模組或嵌入 Python 的穩定 ABI(應用程式二進位介面)現已明確定義。 C API 穩定性 描述了 C API 和 ABI 穩定性保證以及使用穩定 ABI 的最佳實踐。

(由 Petr Viktorin 在 PEP 652bpo-43795 中貢獻。)

新功能

移植到 Python 3.10

  • 現在必須定義 PY_SSIZE_T_CLEAN 巨集以使用 PyArg_ParseTuple()Py_BuildValue() 格式,這些格式使用 #: es#, et#s#u#y#z#U#Z#。請參閱 剖析引數與建置數值PEP 353。(由 Victor Stinner 在 bpo-40943 中貢獻。)

  • 由於 Py_REFCNT() 更改為行內靜態函式 (inline static function),因此 Py_REFCNT(obj) = new_refcnt 必須替換為 Py_SET_REFCNT(obj, new_refcnt) :參見 Py_SET_REFCNT() (自 Python 3.9 起可用)。為了向後相容,可以使用該巨集:

    #if PY_VERSION_HEX < 0x030900A4
    #  define Py_SET_REFCNT(obj, refcnt) ((Py_REFCNT(obj) = (refcnt)), (void)0)
    #endif
    

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

  • 由於過去的種種原因,過去在不持有 GIL 的情況下呼叫 PyDict_GetItem() 是被允許的。目前已被禁止。(由 Victor Stinner 在 bpo-40839 中貢獻。)

  • PyUnicode_FromUnicode(NULL, size)PyUnicode_FromStringAndSize(NULL, size) 現在會引發 DeprecationWarning。請改用 PyUnicode_New() 來分配沒有初始資料的 Unicode 物件。(由 Inada Naoki 在 bpo-36346 中貢獻。)

  • PyCapsule API unicodedata.ucnhash_CAPI 的私有 _PyUnicode_Name_CAPI 結構已移至內部 C API。(由 Victor Stinner 在 bpo-42157 中貢獻。)

  • 如果在 Py_Initialize() 之前(Python 初始化之前)被呼叫,Py_GetPath()Py_GetPrefix()Py_GetExecPrefix()Py_GetProgramFullPath()Py_GetPythonHome()Py_GetProgramName() 現在會回傳 NULL。使用新的 Python初始化配置 API 來獲取 Python 路径配置。(由 Victor Stinner 在 bpo-42260 中貢獻。)

  • PyList_SET_ITEM()PyTuple_SET_ITEM()PyCell_SET() 巨集不能再用作左值 (l-value) 或右值 (r-value)。例如,x = PyList_SET_ITEM(a, b, c)PyList_SET_ITEM(a, b, c) = x 現在會失敗並出現編譯器錯誤。它可以防止如 if (PyList_SET_ITEM (a, b, c) < 0) ... 測試之類的錯誤。(由 Zackery Spytz 和 Victor Stinner 在 bpo-30459 中貢獻。)

  • 非受限 API 檔案 odictobject.hparser_interface.hpicklebufobject.hpyarena.hpyctype.hpydebug.hpyfpe.hpytime.h 已移至 Include/cpython 目錄。這些檔案不得直接被引入,因為它們已於 Python.h 中引入;請參閱 引入檔案 (include files)。如果直接引入它們,請考慮改為引入 Python.h。(由 Nicholas Sim 在 bpo-35134 中貢獻。)

  • 请使用 Py_TPFLAGS_IMMUTABLETYPE 类型旗标来创建不可变类型对象。 请勿依赖于 Py_TPFLAGS_HEAPTYPE 来确定类型对象是否可变;应改为检查是否设置了 Py_TPFLAGS_IMMUTABLETYPE。 (由 Victor Stinner 和 Erlend E. Aasland 在 bpo-43908 中贡献。)

  • 未以說明文件記錄的函式 Py_FrozenMain 已從受限 API 中刪除。該函式主要用於 Python 的自定義建置。(由 Petr Viktorin 在 bpo-26241 中貢獻。)

已棄用

  • PyUnicode_InternImmortal() 函式現已棄用,並將在 Python 3.12 中刪除:請改用 PyUnicode_InternInPlace()。(由 Victor Stinner 在 bpo-41692 中貢獻。)

已刪除

  • 刪除了操作 Py_UNICODE* 字串的 Py_UNICODE_str* 函式。(由 Inada Naoki 在 bpo-41123 中貢獻。)

  • 刪除了 PyUnicode_GetMax()。請改用新的 (PEP 393) API。(由 Inada Naoki 在 bpo-41103 中貢獻。)

  • 刪除了 PyLong_FromUnicode()。請改用 PyLong_FromUnicodeObject()。(由 Inada Naoki 在 bpo-41103 中貢獻。)

  • 刪除了 PyUnicode_AsUnicodeCopy()。請改用 PyUnicode_AsUCS4Copy()PyUnicode_AsWideCharString() (由 Inada Naoki 在 bpo-41103 中貢獻。)

  • 刪除了 _Py_CheckRecursionLimit 變數:它已被 PyInterpreterState 結構的 ceval.recursion_limit 取代。(由 Victor Stinner 在 bpo-41834 中貢獻。)

  • 刪除了未被說明文件記錄的巨集 Py_ALLOW_RECURSIONPy_END_ALLOW_RECURSION 以及 PyInterpreterState 結構的 recursion_ritic 欄位。(由 Serhiy Storchaka 在 bpo-41936 中貢獻。)

  • 刪除了未被說明文件記錄的 PyOS_InitInterrupts() 函式。初始化 Python 已經隱式安裝信號處理程式:請參閱 PyConfig.install_signal_handlers。(由 Victor Stinner 在 bpo-41713 中貢獻。)

  • 刪除 PyAST_Validate() 函式。不再可能使用公開 C API 來建置 AST 物件(mod_ty 類型)。該函式已被排除在受限 C API 之外 (PEP 384)。(由 Victor Stinner 在 bpo-43244 中貢獻。)

  • 刪除 symtable.h 標頭檔和未被說明文件記錄的函式:

    • PyST_GetScope()

    • PySymtable_Build()

    • PySymtable_BuildObject()

    • PySymtable_Free()

    • Py_SymtableString()

    • Py_SymtableStringObject()

    Py_SymtableString() 函式錯誤地成為穩定 ABI 的一部分,但它因為 symtable.h 標頭檔被排除在受限 C API 之外而無法使用。

    請改用 Python symtable 模組。(由 Victor Stinner 在 bpo-43244 中貢獻。)

  • 從受限 C API 標頭和 python3.dll (在 Windows 上提供穩定 ABI 的函式庫)中刪除 PyOS_ReadlineFunctionPointer()。由於該函式採用 FILE* 引數,因此無法保證其 ABI 穩定性。(由 Petr Viktorin 在 bpo-43868 中貢獻。)

  • 刪除 ast.hasdl.hPython-ast.h 標頭檔。這些函式沒有文件記錄,並且被排除在受限 C API 之外。這些標頭檔定義的大多數名稱都沒有前綴 Py,因此可能會產生名稱衝突。例如,Python-ast.h 定義了一個 Yield 巨集,它與 Windows <winbase.h> 標頭使用的 Yield 有名稱衝突。請改用 Python ast 模組。(由 Victor Stinner 在 bpo-43244 中貢獻。)

  • 刪除編譯器和使用 struct _mod 的剖析器函式,因為公開 AST C API 已被刪除:

    • PyAST_Compile()

    • PyAST_CompileEx()

    • PyAST_CompileObject()

    • PyFuture_FromAST()

    • PyFuture_FromASTObject()

    • PyParser_ASTFromFile()

    • PyParser_ASTFromFileObject()

    • PyParser_ASTFromFilename()

    • PyParser_ASTFromString()

    • PyParser_ASTFromStringObject()

    這些函式沒有文件記錄,並且被排除在受限 C API 之外。(由 Victor Stinner 在 bpo-43244 中貢獻。)

  • 刪除包含以下函式的 pyarena.h 標頭檔:

    • PyArena_New()

    • PyArena_Free()

    • PyArena_Malloc()

    • PyArena_AddPyObject()

    這些函式沒有文件記錄、被排除在受限 C API 之外,並僅被編譯器於內部使用。(由 Victor Stinner 在 bpo-43244 中貢獻。)

  • 為了 Python 最佳化,已刪除 PyThreadState.use_tracing 成員。(由 Mark Shannon 在 bpo-43760 中貢獻。)

3.10.7 中的重要安全特性

使用十进制以外的底,如 2(二进制)、4、8(八进制)、16(十六进制)、32 以外作为基数在 intstr 之间进行转换,如果字符串形式的数字数量超过一个限制,会抛出 ValueError,以避免因算法复杂而导致的潜在拒绝服务攻击。这是对 CVE-2020-10735 的缓解方案。这个限制可以通过环境变量、命令行旗标或 sys API 进行配置或禁用。参见 integer string conversion length limitation 文档。默认限制是字符串形式的 4300 位数字。

3.10.8 中的重要安全特性

已被弃用的 mailcap 模块现在将拒绝将不安全的文本(文件名、MIME 类型、形参等)注入到 shell 命令中。 它不会使用此类文本,而是会发出警告并且将视作未找到匹配结果(或者对于测试命令,将视作测试失败)。 (由 Petr Viktorin 在 gh-98966 中贡献。)

3.10.12 中的重要变化

tarfile

  • tarfile 中的提取方法和 shutil.unpack_archive() 都新增了 filter 参数以允许限制可能令人意外或危险的 tar 特性,例如在目标目录之外创建文件。 相关细节参见 解压缩过滤器。 在 Python 3.12 中,不带 filter 参数的用法将显示 DeprecationWarning。 在 Python 3.14 中,默认值将切换为 'data'。 (由 Petr Viktorin 在 PEP 706 中贡献。)