Python 3.10 的新特性 — Python 文档

来自菜鸟教程
Python/docs/3.10/whatsnew/3.10
跳转至:导航、​搜索

Python 3.10 中的新功能

释放
日期
November 21, 2021
编辑
巴勃罗·加林多·萨尔加多

本文解释了 Python 3.10 中与 3.9 相比的新特性。

有关完整详细信息,请参阅 变更日志

摘要 – 发布亮点

新的语法特性:

  • PEP 634,结构模式匹配:规范
  • PEP 635,结构模式匹配:动机和基本原理
  • PEP 636,结构模式匹配:教程
  • :issue:`12782`,现在正式允许带括号的上下文管理器。

标准库中的新功能:

  • PEP 618,添加可选长度检查到 zip。

解释器改进:

  • PEP 626,用于调试和其他工具的精确行号。

新的打字功能:

重要的弃用、删除或限制:

  • PEP 644,需要 OpenSSL 1.1.1 或更新版本
  • PEP 632,弃用 distutils 模块。
  • PEP 623,弃用并准备移除 PyUnicodeObject 中的 wstr 成员。
  • PEP 624,删除 Py_UNICODE 编码器 API
  • PEP 597,添加可选编码警告


新功能

带括号的上下文管理器

现在支持使用括号在上下文管理器中跨多行继续。 这允许以类似于以前使用 import 语句可能的方式在多行中格式化一长串上下文管理器。 例如,所有这些示例现在都有效:

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 在 :issue:`12782`:issue:`40334` 中提供。)


更好的错误信息

语法错误

当解析包含未闭合括号或括号的代码时,解释器现在包括括号未闭合括号的位置,而不是显示 SyntaxError:解析 时出现意外 EOF 或指向某些不正确的位置。 例如,考虑以下代码(注意未闭合的“{”):

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 在 :issue:`42864` 和 Batuhan Taskaya 在 :issue:`40176` 中贡献。)

SyntaxError 解释器引发的异常现在将突出显示构成语法错误本身的表达式的完整错误范围,而不仅仅是检测到问题的位置。 这样,而不是显示(在 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 在 :issue:`43914` 中贡献。

SyntaxError 异常的大量新的专门消息已被合并。 一些最显着的如下:

  • 块前缺少 :

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

    (由 Pablo Galindo 在 中提供:issue:`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 在 中提供:issue:`43017`

  • 集合文字中和表达式之间缺少逗号:

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

    (由 Pablo Galindo 在 中提供:issue:`43822`

  • 不带括号的多种异常类型:

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

    (由 Pablo Galindo 在 中提供:issue:`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 在 中提供:issue:`43823`

  • try 块没有 exceptfinally 块:

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

    (由 Pablo Galindo 在 中提供:issue:`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 在 中提供:issue:`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 在 中提供:issue:`41064`


缩进错误

许多 IndentationError 异常现在有更多关于期望缩进的块类型的上下文,包括语句的位置:

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

属性错误

打印 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 在 中提供:issue:`38530`。)

警告

请注意,如果未调用 PyErr_Display() 来显示错误,则这将不起作用,如果使用其他自定义错误显示函数,则可能会发生这种错误。 这是一些 REPL 中常见的场景,比如 IPython。


名称错误

当打印由解释器引发的 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 在 中提供:issue:`38530`。)

警告

请注意,如果未调用 PyErr_Display() 来显示错误,这将不起作用,如果使用其他一些自定义错误显示函数,则会发生这种情况。 这是一些 REPL 中常见的场景,比如 IPython。


PEP 626:用于调试和其他工具的精确行号

PEP 626 为调试、分析和覆盖工具带来了更精确和可靠的行号。 为所有执行的代码行和仅为执行的代码行生成具有正确行号的跟踪事件。

框架对象的 f_lineno 属性将始终包含预期的行号。

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


PEP 634:结构模式匹配

结构模式匹配已以 匹配语句case 语句 模式的关联动作的形式添加。 模式由序列、映射、原始数据类型以及类实例组成。 模式匹配使程序能够从复杂的数据类型中提取信息,在数据结构上进行分支,并根据不同形式的数据应用特定的操作。

语法和操作

模式匹配的通用语法是:

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

match 语句采用表达式并将其值与作为一个或多个 case 块给出的连续模式进行比较。 具体来说,模式匹配通过以下方式运作:

  1. 使用具有类型和形状的数据(subject
  2. 评估 match 语句中的 subject
  3. 从上到下将主题与 case 语句中的每个模式进行比较,直到确认匹配。
  4. 执行与确认匹配的模式相关联的操作
  5. 如果没有确认完全匹配,最后一种情况,通配符 _(如果提供)将用作匹配情况。 如果未确认完全匹配且不存在通配符大小写,则整个匹配块为空操作。


声明式方法

读者可能会通过使用 C、Java 或 JavaScript(以及许多其他语言)中的 switch 语句将主题(数据对象)与文字(模式)进行匹配的简单示例来了解模式匹配。 switch 语句通常用于将对象/表达式与包含文字的 case 语句进行比较。

在 Scala 和 Elixir 等语言中可以找到更强大的模式匹配示例。 对于结构模式匹配,该方法是“声明性的”并明确说明数据匹配的条件(模式)。

虽然使用嵌套“if”语句的“命令式”系列指令可用于完成类似于结构模式匹配的事情,但不如“声明式”方法清晰。 相反,“声明式”方法声明了匹配要满足的条件,并且通过其显式模式更具可读性。 虽然结构模式匹配可以以其最简单的形式使用,将变量与 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,则返回“我是茶壶”。 如果上述函数传递了 500 的 status,带有 _ 的 case 语句将作为通配符匹配,并返回“互联网出现问题”。 请注意最后一个块:变量名称 _ 充当 通配符 并确保主题始终匹配。 _ 的使用是可选的。

您可以使用 |(“或”)在单个模式中组合多个文字:

case 401 | 403 | 404:
    return "Not allowed"
没有通配符的行为

如果我们通过删除最后一个 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 语句中使用 _,则可能不存在匹配项。 如果不存在匹配项,则行为为空操作。 例如,如果通过 500 的 status,则会发生空操作。


带有文字和变量的模式

模式可能看起来像解包赋值,并且模式可用于绑定变量。 在这个例子中,一个数据点可以解包到它的 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")
具有位置参数的模式

您可以将位置参数与一些为其属性提供排序的内置类一起使用(例如 数据类)。 您还可以通过在类中设置 __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.")

在上述情况下,test_variable 将匹配 ('error', code, 100) 和 ('error', code, 800)。


警卫

我们可以将 if 子句添加到模式中,称为“守卫”。 如果守卫为假,match 继续尝试下一个案例块。 请注意,值捕获发生在评估守卫之前:

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.")

其他主要特点

其他几个主要功能:

  • 与解包赋值一样,元组和列表模式具有完全相同的含义并且实际上匹配任意序列。 从技术上讲,主题必须是一个序列。 因此,一个重要的例外是模式不匹配迭代器。 此外,为了防止常见错误,序列模式不匹配字符串。

  • 序列模式支持通配符:[x, y, *rest](x, y, *rest) 的工作方式类似于解包赋值中的通配符。 *后面的名字也可能是_,所以(x, y, *_)匹配至少两个item的序列,不绑定剩余的item。

  • 映射模式:{"bandwidth": b, "latency": l} 从字典中捕获 "bandwidth""latency" 值。 与序列模式不同,额外的键被忽略。 还支持通配符 **rest。 (但 **_ 是多余的,所以是不允许的。)

  • 可以使用 as 关键字捕获子模式:

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

    这将 x1, y1, x2, y2 绑定到主题的整个第二项,就像您在没有 as 子句的情况下所期望的那样。

  • 大多数文字通过相等进行比较。 但是,单例 TrueFalseNone 是通过身份比较的。

  • 命名常量可以在模式中使用。 这些命名常量必须是点名,以防止常量被解释为捕获变量:

    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


可选 EncodingWarning 和 encoding="locale" 选项

TextIOWrapperopen() 的默认编码取决于平台和语言环境。 由于 UTF-8 用于大多数 Unix 平台,因此在打开 UTF-8 文件时省略 encoding 选项(例如 JSON、YAML、TOML、Markdown)是一个非常常见的错误。 例如:

# 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 为真并且使用特定于语言环境的默认编码时会发出它。

添加了 -X warn_default_encoding 选项和 PYTHONWARNDEFAULTENCODING 以启用警告。

有关详细信息,请参阅 文本编码


其他语言更改

  • int 类型有一个新方法 int.bit_count(),返回给定整数的二进制展开式中 1 的数量,也称为人口计数。 (由 Niklas Fiekas 在 中提供:issue:`29882`。)
  • dict.keys()dict.values()dict.items() 返回的视图现在都有一个 mapping 属性这给出了一个 types.MappingProxyType 包装原始字典的对象。 (由 Dennis Sweeney 在 中提供:问题:`40890`。)
  • PEP 618zip() 函数现在有一个可选的 strict 标志,用于要求所有迭代具有相等的长度。
  • 采用整数参数的内置和扩展函数不再接受 Decimals、Fractions 和其他只能在有损失的情况下转换为整数的对象(例如 具有 __int__() 方法但没有 __index__() 方法)。 (由 Serhiy Storchaka 在 中提供:issue:`37999`。)
  • 如果 object.__ipow__() 返回 NotImplemented,算子将正确回退到 object.__pow__()object.__rpow__() ] 正如预期的那样。 (由 Alex Shkop 在 中提供:问题:`38302`。)
  • 赋值表达式现在可以在集合文字和集合推导式中以及在序列索引(但不是切片)中不加括号地使用。
  • 函数有一个新的 __builtins__ 属性,用于在函数执行时查找内置符号,而不是查找 __globals__['__builtins__']。 如果存在,则从 __globals__["__builtins__"] 初始化该属性,否则从当前内置函数初始化。 (由 Mark Shannon 在 中贡献:issue:`42990`。)
  • 添加了两个新的内置函数 - aiter()anext() 以分别为 iter()next() 提供异步对应项. (由 Joshua Bronson、Daniel Pope 和 Justin Wang 在 :issue:`31861` 中提供。)
  • 静态方法 (@staticmethod) 和类方法 (@classmethod) 现在继承方法属性 (__module__, __name__, __qualname__ ]、__doc____annotations__)并有一个新的 __wrapped__ 属性。 此外,静态方法现在可以作为常规函数调用。 (由 Victor Stinner 在 中提供:问题:`43682`。)
  • 复杂目标的注释(除 PEP 526 定义的 simple name 目标之外的所有内容)不再对 from __future__ import annotations 产生任何运行时影响。 (由 Batuhan Taskaya 在 中贡献:问题:`42737`。)
  • 类和模块对象现在可以根据需要延迟创建空注释字典。 注释字典存储在对象的 __dict__ 中以实现向后兼容。 这改进了使用 __annotations__ 的最佳实践; 有关更多信息,请参阅 注释最佳实践 。 (由 Larry Hastings 在 中提供:问题:`43901`。)
  • 注释包含 yieldyield fromawait 或命名表达式现在由于其副作用而被禁止在 from __future__ import annotations 下。 (由 Batuhan Taskaya 在 中提供:issue:`42725`。)
  • 使用未绑定变量、super() 和其他可能改变符号表处理的表达式作为注释现在在 from __future__ import annotations 下无效。 (由 Batuhan Taskaya 在 中提供:issue:`42725`。)
  • float 类型和 decimal.Decimal 类型的 NaN 值的哈希值现在取决于对象标识。 以前,它们总是散列到 0,即使 NaN 值彼此不相等。 在创建包含多个 NaN 的字典和集合时,由于过多的哈希冲突,这可能导致潜在的二次运行时行为。 (由 Raymond Hettinger 在 中提供:issue:`43475`。)
  • 删除 __debug__ 常量时将引发 SyntaxError(而不是 NameError)。 (由 Dong-hee Na 在 中提供:issue:`45000`。)
  • SyntaxError 异常现在具有 end_linenoend_offset 属性。 如果未确定,它们将是 None。 (由 Pablo Galindo 在 中提供:issue:`43914`。)


新模块

  • 还没有。


改进的模块

异步

添加缺少的 connect_accepted_socket() 方法。 (由 Alex Grönholm 在 :issue:`41332` 中提供。)


参数解析

在 argparse 帮助中,误导性短语“可选参数”被替换为“选项”。 如果某些测试依赖于精确的输出匹配,则可能需要进行调整。 (由 Raymond Hettinger 在 中提供:issue:`9694`。)


大批

array.arrayindex() 方法现在有可选的 startstop 参数。 (由 Anders Lorentsen 和 Zackery Spytz 在 中提供:issue:`31956`。)


asynchat, asyncore, smtpd

自 Python 3.6 起,这些模块已在其模块文档中标记为已弃用。 导入时 DeprecationWarning 现在已添加到所有这三个模块中。


base64

添加 base64.b32hexencode()base64.b32hexdecode() 以支持 Base32 Encoding with Extended Hex Alphabet。


数据表

添加 clearBreakpoints() 以重置所有设置的断点。 (由 Irit Katriel 在 中提供:issue:`24160`。)


一分为二

添加了向 bisect 模块中的 API 提供 key 函数的可能性。 (由 Raymond Hettinger 在 中提供:issue:`4356`。)


编解码器

添加 codecs.unregister() 函数以取消注册编解码器搜索函数。 (由 Hai Shi 在 中提供:issue:`41842`。)


收藏.abc

collections.abc.Callable参数化泛型__args__ 现在与 typing.Callable 一致。 collections.abc.Callable 泛型现在扁平化类型参数,类似于 typing.Callable 目前所做的。 这意味着collections.abc.Callable[[int, str], str]将有(int, str, str)__args__; 以前这是 ([int, str], str)。 为了允许这种更改,现在可以对 types.GenericAlias 进行子类化,并且在为 collections.abc.Callable 类型下标时将返回一个子类。 请注意,对于参数化 collections.abc.Callable 的无效形式,可能会引发 TypeError,这些参数可能已在 Python 3.9 中静默传递。 (由 Ken Jin 在 中提供:issue:`42195`。)


上下文库

添加 contextlib.aclosure() 上下文管理器以安全关闭异步生成器和表示异步释放资源的对象。 (由 Joongi Kim 和 John Belmonte 在 :issue:`41229` 中提供。)

contextlib.nullcontext() 添加异步上下文管理器支持。 (由 Tom Gringauz 在 :issue:`41543` 中贡献。)

添加 AsyncContextDecorator,支持使用异步上下文管理器作为装饰器。


诅咒

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 在 中提供:issue:`36982`。)

BUTTON5_* 常量现在在 curses 模块中公开,如果它们是由底层的 curses 库提供的。 (由 Zackery Spytz 在 中提供:issue:`39273`。)


数据类

__插槽__

dataclasses.dataclass() 装饰器中添加了 slots 参数。 (由 Yurii Karabas 在 中提供:issue:`42269`


仅关键字字段

数据类现在支持在生成的 __init__ 方法中只有关键字的字段。 有多种方法可以指定仅限关键字的字段。

你可以说每个字段都是关键字:

from dataclasses import dataclass

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

namebirthday 都是生成的 __init__ 方法的关键字参数。

您可以在每个字段的基础上指定仅关键字:

from dataclasses import dataclass

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

这里只有 birthday 是仅关键字的。 如果您在单个字段上设置 kw_only,请注意由于仅关键字字段需要遵循非仅关键字字段,因此存在重新排序字段的规则。 有关详细信息,请参阅完整的数据类文档。

您还可以指定 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 不是。 (由埃里克 V 提供。 中的史密斯:问题:`43532`)


分配器

整个 distutils 包已弃用,将在 Python 3.12 中删除。 它指定包构建的功能已经被第三方包 setuptoolspackaging 完全取代,大多数其他常用的 API 都可以在标准库的其他地方使用(例如 platformshutilsubprocesssysconfig)。 没有计划从 distutils 迁移任何其他功能,使用其他功能的应用程序应该计划制作代码的私有副本。 参考 PEP 632 讨论。

Python 3.8 中弃用的 bdist_wininst 命令已被删除。 现在建议使用 bdist_wheel 命令在 Windows 上分发二进制包。 (由 Victor Stinner 在 中提供:问题:`42802`。)


文档测试

当模块没有定义__loader__时,回退到__spec__.loader。 (由 Brett Cannon 在 中贡献:issue:`42133`。)


编码

encodings.normalize_encoding() 现在忽略非 ASCII 字符。 (由 Hai Shi 在 中提供:issue:`39337`。)


文件输入

fileinput.input()fileinput.FileInput 中添加 encodingerrors 参数。 (由 Inada Naoki 在 中提供:issue:`43712`。)

fileinput.hook_compressed() 现在在 mode 为“r”并且文件被压缩时返回 TextIOWrapper 对象,就像未压缩的文件一样。 (由稻田直树在 中提供:issue:`5758`。)


故障处理程序

faulthandler 模块现在可以检测垃圾收集器收集期间是否发生致命错误。 (由 Victor Stinner 在 中提供:问题:`44466`。)


GC

gc.get_objects()gc.get_referrers()gc.get_referents() 添加审计钩子。 (由 Pablo Galindo 在 中提供:issue:`43439`。)


球体

glob()iglob() 中添加 root_dirdir_fd 参数,允许指定搜索的根目录。 (由 Serhiy Storchaka 在 中提供:issue:`38144`。)


哈希库

hashlib 模块需要 OpenSSL 1.1.1 或更新版本。 (由 Christian Heimes 在 PEP 644中提供:issue:`43669`。)

hashlib 模块初步支持 OpenSSL 3.0.0。 (由 Christian Heimes 在 :issue:`38820` 和其他问题中贡献。)

pbkdf2_hmac() 的纯 Python 回退已弃用。 将来 PBKDF2-HMAC 将仅在 Python 构建时支持 OpenSSL 时可用。 (由 Christian Heimes 在 中提供:issue:`43880`。)


海马

hmac 模块现在在内部使用 OpenSSL 的 HMAC 实现。 (由 Christian Heimes 在 中提供:issue:`40645`。)


空闲和空闲库

让 IDLE 调用 sys.excepthook()(在没有“-n”的情况下启动时)。 用户挂钩以前被忽略。 (Ken Hilton 在 中的补丁:问题:`43008`。)

此更改已向后移植到 3.9 维护版本。

添加 Shell 侧边栏。 将主要提示 ('>>>') 移至侧边栏。 将辅助提示 ('...') 添加到侧边栏。 左键单击和可选的拖动选择一行或多行文本,就像编辑器行号侧边栏一样。 选择文本行后右键单击会显示带有“带提示的复制”的上下文菜单。 这将来自侧边栏的提示与所选文本中的行压缩在一起。 此选项也出现在文本的上下文菜单中。 (由 Tal Einat 在 中提供:问题:`37903`。)

使用空格而不是制表符来缩进交互式代码。 这使得交互式代码条目“看起来正确”。 使这成为可能是添加 shell 侧边栏的主要动机。 由 Terry Jan Reedy 在 中提供:issue:`37892`。)

我们希望将这些 shell 更改向后移植到未来的 3.9 维护版本。

在模式匹配语句中突出显示新的 软关键字 matchcase_。 但是,这种突出显示并不完美,在某些极少数情况下会出现错误,包括 case 模式中的某些 _-s。 (由 Tal Einat 在 bpo-44010 中贡献。)


导入库元数据

importlib_metadata 4.6 的功能相同(history)。

importlib.metadata 入口点 现在通过新的 importlib.metadata.EntryPoints 类为按组和名称选择入口点提供更好的体验。 有关弃用和使用的更多信息,请参阅文档中的兼容性说明。

添加了 importlib.metadata.packages_distributions(),用于将顶级 Python 模块和包解析为它们的 importlib.metadata.Distribution


检查

当模块没有定义__loader__时,回退到__spec__.loader。 (由 Brett Cannon 在 中贡献:issue:`42133`。)

添加 inspect.get_annotations(),它可以安全地计算对象上定义的注释。 它解决了访问各种类型对象上的注释的怪癖,并对它检查的对象做出很少的假设。 inspect.get_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 在 中提供:问题:`43817`。)


线缓存

当模块没有定义__loader__时,回退到__spec__.loader。 (由 Brett Cannon 在 中贡献:issue:`42133`。)


操作系统

为 VxWorks RTOS 添加 os.cpu_count() 支持。 (由 Peixing Xin 在 中提供:issue:`41440`。)

添加一个新函数 os.eventfd() 和相关帮助程序,以在 Linux 上封装 eventfd2 系统调用。 (由 Christian Heimes 在 中提供:issue:`41001`。)

添加 os.splice() 允许在两个文件描述符之间移动数据,而无需在内核地址空间和用户地址空间之间进行复制,其中一个文件描述符必须引用管道。 (由 Pablo Galindo 在 中提供:issue:`41625`。)

为 macOS 添加 O_EVTONLYO_FSYNCO_SYMLINKO_NOFOLLOW_ANY。 (由 Dong-hee Na 在 中提供:issue:`43106`。)


操作系统路径

os.path.realpath() 现在接受 strict 仅关键字参数。 当设置为 True 时,如果路径不存在或遇到符号链接循环,则会引发 OSError。 (由 Barney Gale 在 中提供:问题:`43757`。)


路径库

PurePath.parents 添加切片支持。 (由 Joshua Cannon 在 中提供:issue:`35498`

PurePath.parents 添加负索引支持。 (由 Yaroslav Pankovych 在 中提供:issue:`21041`

添加取代 link_to()Path.hardlink_to 方法。 新方法的参数顺序与 symlink_to() 相同。 (由 Barney Gale 在 中提供:issue:`39950`。)

pathlib.Path.stat()chmod() 现在接受 follow_symlinks 关键字参数,以与 os 中的相应函数保持一致] 模块。 (由 Barney Gale 在 中提供:问题:`39906`。)


平台

添加 platform.freedesktop_os_release() 以从 freedesktop.org os-release 标准文件中检索操作系统标识。 (由 Christian Heimes 在 中提供:issue:`28468`


打印

pprint.pprint() 现在接受新的 underscore_numbers 关键字参数。 (由 sblondon 在 中贡献:issue:`42914`。)

pprint 现在可以漂亮地打印 dataclasses.dataclass 实例。 (由 Lewis Gaul 在 中提供:问题:`43080`。)


py_compile

--quiet 选项添加到 py_compile 的命令行界面。 (由 Gregory Schevchenko 在 :issue:`38731` 中贡献。)


pyclbr

end_lineno 属性添加到 pyclbr.readline()pyclbr.readline_ex() 返回的树中的 FunctionClass 对象。 它匹配现有的(开始)lineno。 (由 Aviral Srivastava 在 中提供:issue:`38307`。)


搁置

shelf 模块现在在创建书架时默认使用 pickle.DEFAULT_PROTOCOL 而不是 pickle 协议 3。 (由 Zackery Spytz 在 中提供:issue:`34204`。)


统计数据

添加 covariance()、Pearson 的 correlation() 和简单的 linear_regression() 函数。 (由 Tymoteusz Wołodźko 在 中提供:issue:`38490`。)


地点

当模块没有定义__loader__时,回退到__spec__.loader。 (由 Brett Cannon 在 中贡献:issue:`42133`。)


插座

异常 socket.timeout 现在是 TimeoutError 的别名。 (由 Christian Heimes 在 中提供:问题:`42413`。)

添加使用 IPPROTO_MPTCP 创建 MPTCP 套接字的选项(由 Rui Cunha 在 中贡献:issue:`43571`。)

添加 IP_RECVTOS 选项以接收服务类型 (ToS) 或 DSCP/ECN 字段(由 Georg Sauthoff 在 :issue:`44077` 中贡献。)


ssl

ssl 模块需要 OpenSSL 1.1.1 或更新版本。 (由 Christian Heimes 在 PEP 644中提供:issue:`43669`。)

ssl 模块初步支持 OpenSSL 3.0.0 和新选项 OP_IGNORE_UNEXPECTED_EOF。 (由 Christian Heimes 在 :issue:`38820`:issue:`43794`:issue:`43788`:issue 中贡献:`43791`, :issue:`43799`, :issue:`43920`, :issue:`43789`, 和 [X25] ]:问题:`43811`。)

弃用的函数和弃用的常量的使用现在会导致 DeprecationWarningssl.SSLContext.options 默认设置了 OP_NO_SSLv2OP_NO_SSLv3,因此无法警告再次设置标志。 弃用部分 列出了已弃用的功能。 (由 Christian Heimes 在 中提供:issue:`43880`。)

ssl 模块现在具有更安全的默认设置。 默认情况下禁用没有前向保密或 SHA-1 MAC 的密码。 安全级别 2 禁止安全性低于 112 位的弱 RSA、DH 和 ECC 密钥。 SSLContext 默认为最低协议版本 TLS 1.2。 设置基于 Hynek Schlawack 的研究。 (由 Christian Heimes 在 中提供:issue:`43998`。)

不再正式支持已弃用的协议 SSL 3.0、TLS 1.0 和 TLS 1.1。 Python 不会主动阻止它们。 然而,OpenSSL 构建选项、发行版配置、供应商补丁和密码套件可能会阻止成功握手。

timeout 参数添加到 ssl.get_server_certificate() 函数。 (由 Zackery Spytz 在 中提供:issue:`31870`。)

ssl 模块使用堆类型和多阶段初始化。 (由 Christian Heimes 在 中提供:issue:`42333`。)

添加了新的验证标志 VERIFY_X509_PARTIAL_CHAIN。 (由 中的 l0x 贡献:问题:`40849`。)


sqlite3

connect/handle()enable_load_extension()load_extension() 添加审计事件。 (由 Erlend E 提供。 中的 Aasland:问题:`43762`。)


系统

添加 sys.orig_argv 属性:传递给 Python 可执行文件的原始命令行参数列表。 (由 Victor Stinner 在 中提供:问题:`23427`。)

添加 sys.stdlib_module_names,包含标准库模块名称列表。 (由 Victor Stinner 在 中提供:问题:`42955`。)


_线

_thread.interrupt_main() 现在需要一个可选的信号编号来模拟(默认仍然是 signal.SIGINT)。 (由 Antoine Pitrou 在 中提供:issue:`43356`。)


穿线

添加 threading.gettrace()threading.getprofile() 以检索由 threading.settrace()threading.setprofile() 设置的函数 分别。 (由 Mario Corchero 在 中提供:issue:`42251`。)

添加 threading.__excepthook__ 以允许检索 threading.excepthook() 的原始值,以防它设置为损坏或不同的值。 (由 Mario Corchero 在 中提供:issue:`42308`。)


追溯

format_exception()format_exception_only()print_exception() 函数现在可以将异常对象作为仅位置参数。 (由 Zackery Spytz 和 Matthias Bussonnier 在 :issue:`26389` 中提供。)


类型

重新引入 types.EllipsisTypetypes.NoneTypetypes.NotImplementedType 类,提供一组易于由类型检查器解释的新类型。 (由 Bas van Beek 在 中提供:问题:`41810`。)


打字

有关主要更改,请参阅 与类型提示相关的新功能

typing.Literal 的行为已更改为符合 PEP 586 并匹配 PEP 中指定的静态类型检查器的行为。

  1. Literal 现在删除重复参数。

  2. Literal 对象之间的相等比较现在与顺序无关。

  3. Literal 比较现在尊重类型。 例如,Literal[0] == Literal[False] 先前评估为 True。 现在是 False。 为了支持此更改,内部使用的类型缓存现在支持区分类型。

  4. Literal 对象现在将在相等比较期间引发 TypeError 异常,如果它们的任何参数不是 hashable。 请注意,使用不可散列的参数声明 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 在 中提供:issue:`42345`。)

添加新函数 typing.is_typeddict() 以检查注释是否为 typing.TypedDict。 (由 Patrick Reader 在 中提供:问题:`41792`

仅声明数据变量的 typing.Protocol 的子类现在在使用 isinstance 进行检查时会引发 TypeError,除非它们用 runtime_checkable() 修饰。 以前,这些检查是静默通过的。 如果用户需要运行时协议,他们应该用 runtime_checkable() 装饰器装饰他们的子类。 (由 Yurii Karabas 在 中提供:issue:`38908`

typing.iotyping.re 子模块导入现在将发出 DeprecationWarning。 这些子模块自 Python 3.8 起已被弃用,并将在 Python 的未来版本中删除。 属于这些子模块的任何东西都应该直接从 typing 导入。 (由 Sebastian Rittau 在 中提供:issue:`38291`


单元测试

添加新方法 assertNoLogs() 以补充现有的 assertLogs()。 (由 Kit Yan Choi 在 中提供:issue:`39385`。)


urllib.parse

Python 3.10 之前的 Python 版本允许同时使用 ;& 作为 urllib.parse.parse_qs()urllib.parse.parse_qsl( )。 出于安全考虑,并符合更新的 W3C 建议,这已更改为仅允许单个分隔符键,默认值为 &。 此更改也会影响 cgi.parse()cgi.parse_multipart(),因为它们在内部使用受影响的函数。 有关更多详细信息,请参阅它们各自的文档。 (由 Adam Goldschmidt、Senthil Kumaran 和 Ken Jin 在 :issue:`42967` 中贡献。)

URL 部分中出现的换行符或制表符允许某些形式的攻击。 遵循更新 RFC 3986、ASCII 换行符 \n\r 和制表符 \t 字符的 WHATWG 规范从 URL 中删除由 urllib.parse 中的解析器防止此类攻击。 移除字符由新的模块级变量 urllib.parse._UNSAFE_URL_BYTES_TO_REMOVE 控制。 (参见 :issue:`43882`


xml

LexicalHandler 类添加到 xml.sax.handler 模块。 (由 Jonathan Gossage 和 Zackery Spytz 在 中提供:issue:`35018`。)


压缩导入

添加与PEP 451相关的方法:find_spec()zipimport.zipimporter.create_module()zipimport.zipimporter .exec_module()。 (由 Brett Cannon 在 中贡献:问题:`42131`。)

添加 invalidate_caches() 方法。 (由 Desmond Cheong 在 中提供:issue:`14678`。)


优化

  • 构造函数 str()bytes()bytearray() 现在更快(大约 30-40% f 或小对象)。 (由 Serhiy Storchaka 在 中提供:issue:`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 在 :issue:`41006`:issue:`41718` 中贡献。)
  • LOAD_ATTR 指令现在使用新的“每个操作码缓存”机制。 现在常规属性大约为 36% faster,插槽为 44% faster。 (由 Pablo Galindo 和 Yury Selivanov 在 :issue:`42093` 和 Guido van Rossum 在 :issue:`42927` 贡献,基于最初在 PyPy 和 MicroPython 中实现的想法。)
  • 当使用 --enable-optimizations 构建 Python 时,现在 -fno-semantic-interposition 被添加到编译和链接行。 这将使用 --enable-sharedgcc 创建的 Python 解释器的构建速度提高了 30%。 详情见这篇文章。 (由 Victor Stinner 和 Pablo Galindo 在 中提供:issue:`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 提供,Gregory P. 史密斯,在 :issue:`41486`)
  • 使用字符串化注释时,创建函数时不再创建函数的注释字典。 相反,它们被存储为一个字符串元组,函数对象根据需要懒惰地将其转换为注释字典。 此优化将定义带注释的函数所需的 CPU 时间减少了一半。 (由 Yurii Karabas 和 Inada Naoki 在 中提供:issue:`42202`
  • 子串搜索功能,例如str1 in str2str2.find(str1)现在有时会使用 Crochemore & Perrin 的“双向”字符串搜索算法来避免长字符串上的二次行为。 (由 Dennis Sweeney 在 中提供:issue:`41972`
  • _PyType_Lookup() 添加微优化,以提高常见缓存命中情况下的类型属性缓存查找性能。 这使解释器平均快 1.04 倍。 (由 Dino Viehland 在 中提供:issue:`43452`
  • 以下内置函数现在支持更快的 PEP 590 向量调用约定:map(), filter(), ]reversed()bool()float()。 (由 Dong-hee Na 和 Jeroen Demeyer 在 :issue:`43575`:issue:`43287`:issue:`41922`:issue:`41873`:issue:`41870`)
  • BZ2File 性能通过移除内部 RLock 得到改进。 这使得 BZ2File 线程在面对多个并发读取器或写入器时不安全,就像 gziplzma 中的等效类一直都是一样。 (由 Inada Naoki 在 :issue:`43785` 中提供)。


已弃用


已移除

  • 删除了特殊方法 __int____float____floordiv____mod____divmod____rfloordiv____rmod__ ] 和 复合体 类的 __rdivmod__。 他们总是引发 TypeError。 (由 Serhiy Storchaka 在 中提供:issue:`41974`。)

  • 来自私有和未记录的 _markupbase 模块的 ParserBase.error() 方法已被删除。 html.parser.HTMLParserParserBase 的唯一子类,它的 error() 实现已经在 Python 3.5 中删除了。 (由 Berker Peksag 在 中提供:issue:`31844`。)

  • 删除了 unicodedata.ucnhash_CAPI 属性,它是一个内部 PyCapsule 对象。 相关的私有 _PyUnicode_Name_CAPI 结构已移至内部 C API。 (由 Victor Stinner 在 中提供:问题:`42157`。)

  • 删除了 parser 模块,该模块因切换到新的 PEG 解析器而在 3.9 中被弃用,以及所有仅由旧解析器使用的 C 源文件和头文件,包括 [ X203X]、parser.hgraminit.hgrammar.h

  • 删除了公共 C API 函数 PyParser_SimpleParseStringFlagsPyParser_SimpleParseStringFlagsFilenamePyParser_SimpleParseFileFlagsPyNode_Compile,这些函数因切换到新的 PEG 解析器而在 3.9 中被弃用。

  • 删除了 formatter 模块,该模块在 Python 3.4 中已弃用。 它有点过时,很少使用,也没有经过测试。 它最初计划在 Python 3.6 中删除,但这种删除被推迟到 Python 2.7 EOL 之后。 现有用户应该将他们使用的任何类复制到他们的代码中。 (由 Dong-hee Na 和 Terry J 提供。 中的 Reedy:问题:`42299`。)

  • 删除了 PyModule_GetWarningsModule() 函数,由于 _warnings 模块在 2.6 中被转换为内置模块,因此现在无用。 (由 Hai Shi 在 中提供:issue:`42599`。)

  • collections 模块中删除 Collections Abstract Base Classes 的弃用别名。 (由 Victor Stinner 在 中提供:问题:`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 在 :issue:`42392` 中提供。)


移植到 Python 3.10

本节列出了可能需要更改您的代码的先前描述的更改和其他错误修正。

Python 语法的变化

  • 如果数字文字后紧跟关键字(如 0in x),则在编译以前有效的语法时会发出弃用警告。 在以后的版本中,它将更改为语法警告,最后更改为语法错误。 要消除警告并使代码与未来版本兼容,只需在数字文字和以下关键字之间添加一个空格。 (由 Serhiy Storchaka 在 :issue:`43833` 中贡献)。


Python API 的变化


C API 的变化

  • C API 函数 PyParser_SimpleParseStringFlagsPyParser_SimpleParseStringFlagsFilenamePyParser_SimpleParseFileFlagsPyNode_Compile 和这些函数使用的类型 struct _node 被删除切换到新的 PEG 解析器。

    现在应该使用例如 Py_CompileString() 将源代码直接编译为代码对象。 然后可以使用例如 PyEval_EvalCode() 评估生成的代码对象。

    具体来说:

    • PyParser_SimpleParseStringFlags 后跟 PyNode_Compile 的调用可以通过调用 Py_CompileString() 来代替。

    • PyParser_SimpleParseFileFlags 没有直接替代品。 要从 FILE * 参数编译代码,您需要在 C 中读取文件并将结果缓冲区传递给 Py_CompileString()

    • 要编译给定 char * 文件名的文件,请显式打开该文件,读取它并编译结果。 一种方法是使用 io 模块与 PyImport_ImportModule()PyObject_CallMethod()、PyBytes_AsString()[X145X] 和 [X145X] 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 指令现在接受一个 dict 或一个字符串元组作为函数的注释。 (由 Yurii Karabas 和 Inada Naoki 在 中提供:issue:`42202`


构建更改


C API 更改

PEP 652:保持稳定的 ABI

现在明确定义了用于扩展模块或嵌入 Python 的稳定 ABI(应用程序二进制接口)。 C API 稳定性 描述了 C API 和 ABI 稳定性保证以及使用稳定 ABI 的最佳实践。

(由 Petr Viktorin 在 PEP 652:issue:`43795` 中贡献。)


新功能


移植到 Python 3.10


已弃用


已移除