Python 3.10 有什么新变化

  • 编者:
  • Pablo Galindo Salgado

这篇文章介绍了 Python 3.10 相比 3.9 增加的新特性。 Python 3.10 发布于 2021 年 10 月 14 日。 更详细的信息可参阅 更新日志

摘要 — 发布重点

新的语法特性:

标准库中的新特性:

解释器的改进:

新的类型标注特性:

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

新的特性

带圆括号的上下文管理器

现在已支持使用外层圆括号来使多个上下文管理器可以连续多行地书写。 这允许将过长的上下文管理器集能够以与之前 import 语句类似的方式格式化为多行的形式。 例如,以下这些示例写法现在都是有效的:

  1. with (CtxManager() as example):
  2. ...
  3.  
  4. with (
  5. CtxManager1(),
  6. CtxManager2()
  7. ):
  8. ...
  9.  
  10. with (CtxManager1() as example,
  11. CtxManager2()):
  12. ...
  13.  
  14. with (CtxManager1(),
  15. CtxManager2() as example):
  16. ...
  17.  
  18. with (
  19. CtxManager1() as example1,
  20. CtxManager2() as example2
  21. ):
  22. ...

在被包含的分组末尾过可以使用一个逗号作为结束:

  1. with (
  2. CtxManager1() as example1,
  3. CtxManager2() as example2,
  4. CtxManager3() as example3,
  5. ):
  6. ...

这个新语法使用了新解析器的非 LL(1) 功能。 请查看 PEP 617 [https://peps.python.org/pep-0617/] 来了解更多细节。

(由 Guido van Rossum, Pablo Galindo 和 Lysandros Nikolaou 在 bpo-12782 [https://bugs.python.org/issue?@action=redirect&bpo=12782] 和 bpo-40334 [https://bugs.python.org/issue?@action=redirect&bpo=40334] 中贡献。)

更清楚的错误消息

SyntaxError

现在当解析包含有未关闭括号的代码时解释器会包括未关闭括号的位置而不是显示 SyntaxError: unexpected EOF while parsing 并指向某个不正确的位置。 例如,考虑以下代码(注意未关闭的 “ { ”):

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

之前版本的解释器会报告令人迷惑的语法错误位置:

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

但在 Python 3.10 中则会发出信息量更多的错误提示:

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

类似地,涉及未关闭字符串字面值 (单重引号和三重引号) 的错误现在会指向字符串的开头而不是报告 EOF/EOL。

这些改进的灵感来自 PyPy 解释器之前所进行的工作。

(由 Pablo Galindo 在 bpo-42864 [https://bugs.python.org/issue?@action=redirect&bpo=42864] 以及 Batuhan Taskaya 在 bpo-40176 [https://bugs.python.org/issue?@action=redirect&bpo=40176] 中贡献。)

解释器所引发的 SyntaxError 异常现在将高亮构成语法错误本身的完整异常错误内容,而不是仅提示检测到问题的位置。 这样,不再(同 Python 3.10 之前那样)仅显示:

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

现在 Python 3.10 将这样显示异常:

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

这个改进是由 Pablo Galindo 在 bpo-43914 [https://bugs.python.org/issue?@action=redirect&bpo=43914] 中贡献的。

大量新增的专门化 SyntaxError 异常消息已被添加。 其中最主要的一些如下所示:

  • 在代码块之前缺失 :
  1. >>> if rocket.position > event_horizon
  2. File "<stdin>", line 1 if rocket.position > event_horizon ^
  3. SyntaxError: expected ':'

(由 Pablo Galindo 在 bpo-42997 [https://bugs.python.org/issue?@action=redirect&bpo=42997] 中贡献。)

  • 在推导式的目标中有不带圆括号的元组:
  1. >>> {x,y for x,y in zip('abcd', '1234')}
  2. File "<stdin>", line 1 {x,y for x,y in zip('abcd', '1234')} ^
  3. SyntaxError: did you forget parentheses around the comprehension target?

(由 Pablo Galindo 在 bpo-43017 [https://bugs.python.org/issue?@action=redirect&bpo=43017] 中贡献。)

  • 在多项集字面值中和表达式之间缺失逗号:
  1. >>> items = {
  2. ... x: 1,
  3. ... y: 2
  4. ... z: 3,
  5. File "<stdin>", line 3 y: 2 ^
  6. SyntaxError: invalid syntax. Perhaps you forgot a comma?

(由 Pablo Galindo 在 bpo-43822 [https://bugs.python.org/issue?@action=redirect&bpo=43822] 中贡献。)

  • 多个异常类型不带圆括号:
  1. >>> try:
  2. ... build_dyson_sphere()
  3. ... except NotEnoughScienceError, NotEnoughResourcesError:
  4. File "<stdin>", line 3 except NotEnoughScienceError, NotEnoughResourcesError: ^
  5. SyntaxError: multiple exception types must be parenthesized

(由 Pablo Galindo 在 bpo-43149 [https://bugs.python.org/issue?@action=redirect&bpo=43149] 中贡献。)

  • 字典字面值中缺失 : 和值:
  1. >>> values = {
  2. ... x: 1,
  3. ... y: 2,
  4. ... z:
  5. ... }
  6. File "<stdin>", line 4 z: ^
  7. SyntaxError: expression expected after dictionary key and ':'
  8.  
  9. >>> values = {x:1, y:2, z w:3}
  10. File "<stdin>", line 1 values = {x:1, y:2, z w:3} ^
  11. SyntaxError: ':' expected after dictionary key

(由 Pablo Galindo 在 bpo-43823 [https://bugs.python.org/issue?@action=redirect&bpo=43823] 中贡献。)

  • try 代码块不带 exceptfinally 代码块:
  1. >>> try:
  2. ... x = 2
  3. ... something = 3
  4. File "<stdin>", line 3 something = 3 ^^^^^^^^^
  5. SyntaxError: expected 'except' or 'finally' block

(由 Pablo Galindo 在 bpo-44305 [https://bugs.python.org/issue?@action=redirect&bpo=44305] 中贡献。)

  • 在比较中使用 = 而不是 ==
  1. >>> if rocket.position = event_horizon:
  2. File "<stdin>", line 1 if rocket.position = event_horizon: ^
  3. SyntaxError: cannot assign to attribute here. Maybe you meant '==' instead of '='?

(由 Pablo Galindo 在 bpo-43797 [https://bugs.python.org/issue?@action=redirect&bpo=43797] 中贡献。)

  • 在 f-字符串中使用 *
  1. >>> f"Black holes {*all_black_holes} and revelations"
  2. File "<stdin>", line 1 (*all_black_holes) ^
  3. SyntaxError: f-string: cannot use starred expression here

(由 Pablo Galindo 在 bpo-41064 [https://bugs.python.org/issue?@action=redirect&bpo=41064] 中贡献。)

IndentationError

许多 IndentationError 异常现在具有更多上下文来提示是何种代码块需要缩进,包括语句的位置:

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

AttributeError

当打印 AttributeError 时,PyErr_Display() 将提供引发异常的对象中类似属性名称的建议:

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

(由 Pablo Galindo 在 bpo-38530 [https://bugs.python.org/issue?@action=redirect&bpo=38530] 中贡献。)

警告

请注意如果未调用 PyErr_Display() 来显示错误则此特性将没有效果,这可能发生在使用了某些其他自定义错误显示函数的时候。 这在某些 REPLs 例如 IPython 上是一种常见的情况。

NameError

当打印由解释器引发的 NameError 时,PyErr_Display() 将提供引发异常的函数中类似变量名称的建议:

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

(由 Pablo Galindo 在 bpo-38530 [https://bugs.python.org/issue?@action=redirect&bpo=38530] 中贡献。)

警告

请注意如果未调用 PyErr_Display() 来显示错误则此特性将没有效果,这可能发生在使用了某些其他自定义错误显示函数的时候。 这在某些 REPL 例如 IPython 上是一种常见的情况。

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

PEP 626 带来了更精确可靠的行号用于调试、性能分析和测试工具。 所有被执行的代码行都会并且只有被执行的代码行才会生成带有正确行号的追踪事件。

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

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

PEP 634:结构化模式匹配

增加了采用模式加上相应动作的 match 语句case 语句 的形式的结构化模式匹配。 模式由序列、映射、基本数据类型以及类实例构成。 模式匹配使得程序能够从复杂的数据类型中提取信息、根据数据结构实现分支,并基于不同的数据形式应用特定的动作。

语法与操作

模式匹配的通用语法如下:

  1. match subject:
  2. case <pattern_1>:
  3. <action_1>
  4. case <pattern_2>:
  5. <action_2>
  6. case <pattern_3>:
  7. <action_3>
  8. case _:
  9. <action_wildcard>

match 语句接受一个表达式并将其值与以一个或多个 case 语句块形式给出的一系列模式进行比较。 具体来说,模式匹配的操作如下:

  • 使用具有特定类型和形状的数据 (subject)

  • 针对 subjectmatch 语句中求值

  • 从上到下对 subject 与 case 语句中的每个模式进行比较直到确认匹配到一个模式。

  • 执行与被确认匹配的模式相关联的动作。

  • 如果没有确认到一个完全的匹配,则如果提供了使用通配符 _ 的最后一个 case 语句,则它将被用作已匹配模式。 如果没有确认到一个完全的匹配并且不存在使用通配符的 case 语句,则整个 match 代码块不执行任何操作。

声明性方式

读者可能是通过 C, Java 或 JavaScript (以及其他许多语言) 中的 switch 语句将一个目标 (数据对象) 与一个字面值 (模式) 进行匹配的简单例子了解到模式匹配的概念的。 switch 语句常常被用来将一个对象/表达式与包含在 case 语句中的字面值进行比较。

更强大的模式匹配例子可以在 Scala 和 Elixir 等语言中找到。 这种结构化模式匹配方式是“声明性”的并且会显式地为所要匹配的数据指定条件(模式)。

虽然使用嵌套的“if”语句的“命令性”系列指令可以被用来完成类似结构化模式匹配的效果,但它没有“声明性”方式那样清晰。 相反地,“声明性”方式指定了一个匹配所要满足的条件,并且通过其显式的模式使之更为易读。 虽然结构化模式匹配可以采取将一个变量与一个 case 语句中的字面值进行比较的最简单形式来使用,但它对于 Python 的真正价值在于其针对目标类型和形状的处理操作。

简单模式:匹配一个字面值

让我们把这个例子看作是模式匹配的最简单形式:一个值,即主词,被匹配到几个字面值,即模式。在下面的例子中,status 是匹配语句的主词。模式是每个 case 语句,字面值代表请求状态代码。匹配后,将执行与该 case 相关的动作:

  1. def http_error(status):
  2. match status:
  3. case 400:
  4. return "Bad request"
  5. case 404:
  6. return "Not found"
  7. case 418:
  8. return "I'm a teapot"
  9. case _:
  10. return "Something's wrong with the internet"

如果传给上述函数的 status 为 418,则会返回 "I'm a teapot"。 如果传给上述函数的 status 为 500,则带有 _ 的 case 语句将作为通配符匹配,并会返回 "Something's wrong with the internet"。 请注意最后一个代码块:变量名 _ 将作为 通配符 并确保目标将总是被匹配。 _ 的使用是可选的。

你可以使用 | (“ or ”)在一个模式中组合几个字面值:

  1. case 401 | 403 | 404:
  2. return "Not allowed"
无通配符的行为

如果我们修改上面的例子,去掉最后一个 case 块,这个例子就变成:

  1. def http_error(status):
  2. match status:
  3. case 400:
  4. return "Bad request"
  5. case 404:
  6. return "Not found"
  7. case 418:
  8. return "I'm a teapot"

如果不在 case 语句中使用 _,可能会出现不存在匹配的情况。如果不存在匹配,则行为是一个 no-op。例如,如果传入了值为 500 的 status ,就会发生 no-op。

带有字面值和变量的模式

模式可以看起来像解包形式,而且模式可以用来绑定变量。在这个例子中,一个数据点可以被解包为它的 x 坐标和 y 坐标:

  1. # point 是一个 (x, y) 元组
  2. match point:
  3. case (0, 0):
  4. print("Origin")
  5. case (0, y):
  6. print(f"Y={y}")
  7. case (x, 0):
  8. print(f"X={x}")
  9. case (x, y):
  10. print(f"X={x}, Y={y}")
  11. case _:
  12. raise ValueError("Not a point")

第一个模式有两个字面值 (0, 0) ,可以看作是上面所示字面值模式的扩展。接下来的两个模式结合了一个字面值和一个变量,而变量 绑定 了一个来自主词的值(point)。 第四种模式捕获了两个值,这使得它在概念上类似于解包赋值 (x, y) = point

模式和类

如果你使用类来结构化你的数据,你可以使用类的名字,后面跟一个类似构造函数的参数列表,作为一种模式。这种模式可以将类的属性捕捉到变量中:

  1. class Point:
  2. x: int
  3. y: int
  4.  
  5. def location(point):
  6. match point:
  7. case Point(x=0, y=0):
  8. print("Origin is the point's location.")
  9. case Point(x=0, y=y):
  10. print(f"Y={y} and the point is on the y-axis.")
  11. case Point(x=x, y=0):
  12. print(f"X={x} and the point is on the x-axis.")
  13. case Point():
  14. print("The point is located somewhere else on the plane.")
  15. case _:
  16. print("Not a point")
带有位置参数的模式

你可以在某些为其属性提供了排序的内置类(例如 dataclass)中使用位置参数。 你也可以通过在你的类中设置 __match_args__ 特殊属性来为模式中的属性定义一个专门的位置。 如果它被设为 ("x", "y"),则以下模式均为等价的(并且都是将 y 属性绑定到 var 变量):

  1. Point(1, var)
  2. Point(1, y=var)
  3. Point(x=1, y=var)
  4. Point(y=var, x=1)

嵌套模式

模式可以任意地嵌套。 例如,如果我们的数据是由点组成的短列表,则它可以这样被匹配:

  1. match points:
  2. case []:
  3. print("No points in the list.")
  4. case [Point(0, 0)]:
  5. print("The origin is the only point in the list.")
  6. case [Point(x, y)]:
  7. print(f"A single point {x}, {y} is in the list.")
  8. case [Point(0, y1), Point(0, y2)]:
  9. print(f"Two points on the Y axis at {y1}, {y2} are in the list.")
  10. case _:
  11. print("Something else is found in the list.")

复杂模式和通配符

到目前为止,这些例子仅在最后一个 case 语句中使用了 _。 但通配符可以被用在更复杂的模式中,例如 ('error', code, _)。 举例来说:

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

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

约束项

我们可以向一个模式添加 if 子句,称为“约束项”。 如果约束项为假值,则 match 将继续尝试下一个 case 语句块。 请注意值的捕获发生在约束项被求值之前。:

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

其他关键特性

一些其他关键特性:

  • 类似于解包赋值,元组和列表模式具有完全相同的含义,而且实际上能匹配任意序列。 从技术上说,目标必须为一个序列。 因而,一个重要的例外是模式不能匹配迭代器。 而且,为了避免一个常见的错误,序列模式不能匹配字符串。

  • 序列模式支持通配符: [x, y, *rest](x, y, *rest) 的作用类似于解包赋值中的通配符。 在 * 之后的名称也可以为 _,因此 (x, y, *_) 可以匹配包含两个条目的序列而不必绑定其余的条目。

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

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

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

x1, y1, x2, y2 等绑定就如你在没有 as 子句的情况下所期望的,而 p2 会绑定目标的整个第二项。

  • 大多数字面值是按相等性比较的。 但是,单例对象 True, FalseNone 则是按标识号比较的。

  • 命名常量也可以在模式中使用。 这些命名常量必须为带点号的名称以防止常量被解读为捕获变量:

  1. from enum import Enum
  2. class Color(Enum):
  3. RED = 0
  4. GREEN = 1
  5. BLUE = 2
  6.  
  7. color = Color.GREEN
  8. match color:
  9. case Color.RED:
  10. print("I see red!")
  11. case Color.GREEN:
  12. print("Grass is green")
  13. case Color.BLUE:
  14. print("I'm feeling the blues :(")

完整规格说明参见 PEP 634 [https://peps.python.org/pep-0634/]。 动机与理由参见 PEP 635 [https://peps.python.org/pep-0635/],更详细的教程参见 PEP 636 [https://peps.python.org/pep-0636/]。

可选的 EncodingWarningencoding="locale" 选项

TextIOWrapperopen() 的默认编码格式取决于具体的平台和语言区域设置。 由于 UTF-8 被用于大多数 Unix 平台,当打开 UTF-8 文件(例如 JSON, YAML, TOML, Markdown)时省略 encoding 是一种相当常见的程序错误。 例如:

  1. # 程序错误:应当使用 "rb" 模式或 encoding="utf-8".
  2. with open("data.json") as f:
  3. data = json.load(f)

为了便于查找此类错误,增加了可选的 EncodingWarning。 它会在 sys.flags.warn_default_encoding 为真值并使用了语言区域指定的默认编码格式时被发出。

增加了 -X warn_default_encoding 选项和 PYTHONWARNDEFAULTENCODING 来启用相应警告。

请参阅 文本编码格式 了解更多信息。

有关类型提示的新增特性

本节介绍了涉及 PEP 484 [https://peps.python.org/pep-0484/] 类型提示和 typing 模块的主要改变。

PEP 604: 新的类型联合运算符

引入了启用 X | Y 语法的类型联合运算符。 这提供了一种表示 '类型 X 或类型 Y' 的相比使用 typing.Union 更清晰的方式,特别是在类型提示中。

在之前的 Python 版本中,要为可接受多种类型参数的函数应用类型提示,使用的是 typing.Union:

  1. def square(number: Union[int, float]) -> Union[int, float]:
  2. return number ** 2

类型提示现在可以使用更简洁的写法:

  1. def square(number: int | float) -> int | float:
  2. return number ** 2

这个新增语法也被接受作为 isinstance()issubclass() 的第二个参数:

  1. >>> isinstance(1, int | str)
  2. True

详情参见 union 类型PEP 604 [https://peps.python.org/pep-0604/]。

(由 Maggie Moss 和 Philippe Prados 在 bpo-41428 [https://bugs.python.org/issue?@action=redirect&bpo=41428] 中贡献,并由 Yurii Karabas 和 Serhiy Storchaka 在 bpo-44490 [https://bugs.python.org/issue?@action=redirect&bpo=44490] 中补充。)

PEP 612: 形参规格变量

typing 模块中新增了两个选项以改进用于 PEP 484 [https://peps.python.org/pep-0484/] 的 Callable 提供给静态类型检查器的信息。

第一个选项是形参规格变量。 它们被用来将一个可调用对象的形参类型转发给另一个可调用对象 —— 这种模式常见于高阶函数和装饰器。 使用示例可在 typing.ParamSpec 中找到。 在之前版本中,没有一种简单办法能以如此精确的方式对形参类型的依赖性进行类型标注。

第二个选项是新的 Concatenate 运算符。 它与形参规格变量一起使用以便对增加或移除了其他可调用对象的高阶可调用对象进行类型标注。 使用示例可以在 typing.Concatenate 中找到。

请参阅 typing.Callable, typing.ParamSpec, typing.Concatenate, typing.ParamSpecArgs, typing.ParamSpecKwargsPEP 612 [https://peps.python.org/pep-0612/] 来了解更多细节。

(由 Ken Jin 在 bpo-41559 [https://bugs.python.org/issue?@action=redirect&bpo=41559] 中贡献,并由 Jelle Zijlstra 在 bpo-43783 [https://bugs.python.org/issue?@action=redirect&bpo=43783] 中加以少量改进。 PEP 由 Mark Mendoza 撰写。)

PEP 613: 类型别名

PEP 484 [https://peps.python.org/pep-0484/] 引入了类型别名的概念,只要求它们是不带标注的最高层级赋值。 这种简单性有时会使得类型检查器难以区分类型别名和普通赋值,特别是当涉及到前向引用或无效类型的时候。 例如在比较:

  1. StrCache = 'Cache[str]' # 类型别名
  2. LOG_PREFIX = 'LOG[DEBUG]' # 模块常量

现在 typing 模块具有一个特殊值 TypeAlias 可让你更明确地声明类型别名:

  1. StrCache: TypeAlias = 'Cache[str]' # 类型别名
  2. LOG_PREFIX = 'LOG[DEBUG]' # 模块常量

请参阅 PEP 613 [https://peps.python.org/pep-0613/] 了解详情。

(由 Mikhail Golubev 在 bpo-41923 [https://bugs.python.org/issue?@action=redirect&bpo=41923] 中贡献。)

PEP 647: 用户自定义的类型保护器

TypeGuard 已被添加到 typing 模块用来标注类型保护函数并改进在类型细化期间提供给静态类型检查器的信息。 要了解更多信息,请参阅 TypeGuard 的文档以及 PEP 647 [https://peps.python.org/pep-0647/]。

(由 Ken Jin 和 Guido van Rossum 在 bpo-43766 [https://bugs.python.org/issue?@action=redirect&bpo=43766] 中贡献。 PEP 由 Eric Traut 撰写。)

其他语言特性修改

新增模块

  • 无。

改进的模块

asyncio

加入了缺失的 connect_accepted_socket() 方法。(由 Alex Grönholm 在 bpo-41332 [https://bugs.python.org/issue?@action=redirect&bpo=41332] 中贡献)

argparse

在 argparse 的帮助中,将“可选参数”这一误导性短语改为“可选项”。某些测试代码如果依赖精确的输出匹配,可能需要调整。(由 Raymond Hettinger 在 bpo-9694 [https://bugs.python.org/issue?@action=redirect&bpo=9694] 中贡献)

array

现在, array.arrayindex() 方法拥有可选的 startstop 参数。(由 Anders Lorentsen 和 Zackery Spytz 在 bpo-31956 [https://bugs.python.org/issue?@action=redirect&bpo=31956] 中贡献)

asynchat、asyncore 和 smtpd

从 Python 3.6 开始,这些模块在其文档中已被标为废弃。现在这三个模块都增加了一个导入时警告 DeprecationWarning

base64

增加 base64.b32hexencode()base64.b32hexdecode() 以支持带有扩展十六进制字母的 Base32 编码。

bdb

增加 clearBreakpoints() ,用于重置所有已设断点。(由 Irit Katriel 在 bpo-24160 [https://bugs.python.org/issue?@action=redirect&bpo=24160] 中贡献)

bisect

增加了为 bisect 模块中的 API 提供 key 函数的可能性。(由 Raymond Hettinger 在 bpo-4356 [https://bugs.python.org/issue?@action=redirect&bpo=4356] 中贡献。)

编码器

增加一个 codecs.unregister() 函数,用于取消对编解码器搜索函数的注册。(由 Hai Shi 在 bpo-41842 [https://bugs.python.org/issue?@action=redirect&bpo=41842] 中贡献)

collections.abc

现在, parameterized genericcollections.abc.Callable__args__typing.Callable 一致了。 collections.abc.Callable generic 现在将类型参数扁平化了,类似于 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 在 bpo-42195 [https://bugs.python.org/issue?@action=redirect&bpo=42195] 中贡献)

contextlib

增加了一个上下文管理器 contextlib.aclosing() ,以便能安全关闭异步生成器和代表异步释放资源的对象。(由 Joongi Kim 和 John Belmonte 在 bpo-41229 [https://bugs.python.org/issue?@action=redirect&bpo=41229] 中贡献)

contextlib.nullcontext() 加入异步上下文管理器支持。由 Tom Gringauz 在 bpo-41543 [https://bugs.python.org/issue?@action=redirect&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 [https://bugs.python.org/issue?@action=redirect&bpo=36982] 中贡献)

现在常量 BUTTON5_* 如果是由底层的 curses 库提供的,则会在 curses 模块中体现。(由 Zackery Spytz 在 bpo-39273 [https://bugs.python.org/issue?@action=redirect&bpo=39273] 中贡献)

dataclasses

slots

dataclasses.dataclass() 装饰器中添加 slots 参数。(由 Yurii Karabas 在 bpo-42269 [https://bugs.python.org/issue?@action=redirect&bpo=42269] 中贡献)

仅限关键字字段

数据类现在支持在生成的 init 方法中只用关键字的字段。 有许多方法可以指定只用关键字的字段。

你可以说每一个字段都是仅限关键字的:

  1. from dataclasses import dataclass
  2.  
  3. @dataclass(kw_only=True)
  4. class Birthday:
  5. name: str
  6. birthday: datetime.date

namebirthday 都是生成的 init 方法的仅限关键字的参数。

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

  1. from dataclasses import dataclass, field
  2.  
  3. @dataclass
  4. class Birthday:
  5. name: str
  6. birthday: datetime.date = field(kw_only=True)

这里的只有 birthday 是仅限关键字。如果你在单个字段上设置 kw_only ,要注意由于仅限关键字的字段需要跟在非仅限关键字的字段后面,所以有关于重新排序的规则。 详情请看完整的数据类文件。

你也可以指定 KW_ONLY 标记后面的所有字段都是仅限关键字的。 这可能是最常见的用法:

  1. from dataclasses import dataclass, KW_ONLY
  2.  
  3. @dataclass
  4. class Point:
  5. x: float
  6. y: float
  7. _: KW_ONLY
  8. z: float = 0.0
  9. t: float = 0.0

在这里,zt 是仅限关键字形参,而 xy 不是。 (由 Eric V. Smith 在 bpo-43532 [https://bugs.python.org/issue?@action=redirect&bpo=43532] 中贡献。)

distutils

整个 distutils 包已被废弃,将在 Python 3.12 中移除。其用指定包构建程序的功能已被第三方软件包 setuptoolspackaging 完全取代,而且大多数其他常用的 API 在标准库的其他地方都可以调用(如 platformshutilsubprocesssysconfig)。目前没有迁移 distutils 其他功能的计划,用到其他功能的应用程序应该准备好自己保留一份拷贝。请参考 PEP 632 [https://peps.python.org/pep-0632/] 。

在 Python 3.8 中废弃的 bdist_wininst 命令已被移除。现在在 Windows 中发布二进制包推荐采用 bdist_wheel 命令。(由 Victor Stinner 在 bpo-42802 [https://bugs.python.org/issue?@action=redirect&bpo=42802] 中贡献)

doctest

若模块中没有定义 __loader__ ,则回退至使用 __spec__.loader 。(由 Brett Cannon 在 bpo-42133 [https://bugs.python.org/issue?@action=redirect&bpo=42133] 中贡献)

encodings

现在 encodings.normalize_encoding() 会忽略非 ASCII 字符。(由 Hai Shi 在 bpo-39337 [https://bugs.python.org/issue?@action=redirect&bpo=39337] 中贡献)

enum

Enum __repr__() 现在返回 enum_name.member_name__str__() 现在返回 member_name。 作为模块常量提供的标准库枚举的 repr()module_name.member_name。 (由 Ethan Furman 在 bpo-40066 [https://bugs.python.org/issue?@action=redirect&bpo=40066] 中贡献。)

增加 enum.StrEnum 用于所有成员均为字符串的枚举。 (由 Ethan Furman 在 bpo-41816 [https://bugs.python.org/issue?@action=redirect&bpo=41816] 中贡献。)

fileinput

fileinput.input()fileinput.FileInput 中增加了 encodingerrors 形参。 (由 Inada Naoki 在 bpo-43712 [https://bugs.python.org/issue?@action=redirect&bpo=43712] 中贡献。)

现在 fileinput.hook_compressed() 会在 mode 为 "r" 且文件被压缩时返回 TextIOWrapper 对象,与未压缩文件一样。 (由 Inada Naoki 在 bpo-5758 [https://bugs.python.org/issue?@action=redirect&bpo=5758] 中贡献。)

faulthandler

现在 faulthandler 模块会检测在垃圾回收期间是否发生严重错误。 (由 Victor Stinner 在 bpo-44466 [https://bugs.python.org/issue?@action=redirect&bpo=44466] 中贡献)

gc

gc.get_objects(), gc.get_referrers()gc.get_referents() 添加了审计钩子。 (由 Pablo Galindo 在 bpo-43439 [https://bugs.python.org/issue?@action=redirect&bpo=43439] 中贡献。)

glob

glob()iglob() 中增加了 root_dirdir_fd 形参,用于指定搜索的根目录。(由 Serhiy Storchaka 在 bpo-38144 [https://bugs.python.org/issue?@action=redirect&bpo=38144] 中贡献)

hashlib

hashlib 模块要求 OpenSSL 1.1.1 或更新版本。 (由 Christian Heimes 在 PEP 644 [https://peps.python.org/pep-0644/] 和 bpo-43669 [https://bugs.python.org/issue?@action=redirect&bpo=43669] 中贡献。)

hashlib 模块已初步支持 OpenSSL 3.0.0。 (由 Christian Heimes 在 bpo-38820 [https://bugs.python.org/issue?@action=redirect&bpo=38820] 及其他问题事项中贡献。)

纯 Python 的回退版 pbkdf2_hmac() 已被弃用。 未来 PBKDF2-HMAC 将仅在 Python 带有 OpenSSL 编译时才可用。(由 Christian Heimes 在 bpo-43880 [https://bugs.python.org/issue?@action=redirect&bpo=43880] 中贡献)

hmac

现在 hmac 模块会在内部使用 OpenSSL 的 HMAC 实现。 (由 Christian Heimes 在 bpo-40645 [https://bugs.python.org/issue?@action=redirect&bpo=40645] 中贡献。)

IDLE 与 idlelib

使 IDLE 调用 sys.excepthook() (当启动时没有 '-n' )。用户钩子以前是被忽略的。 (由 Ken Hilton 在 bpo-43008 [https://bugs.python.org/issue?@action=redirect&bpo=43008] 中贡献。)

重新安排设置对话框。 将常规选项卡分成 Windows 和 Shell/Ed 选项卡。 将扩展帮助菜单的帮助源移至扩展标签。为新选项留出空间,并缩短对话框。后者使对话框更适合小屏幕。 (由 Terry Jan Reedy 贡献于 bpo-40468 [https://bugs.python.org/issue?@action=redirect&bpo=40468] 。) 将缩进空间设置从字体标签移到新的 Windows 标签。 (由 Mark Roseman 和 Terry Jan Reedy 在 bpo-33962 [https://bugs.python.org/issue?@action=redirect&bpo=33962] 中提供)。

上述变化已被反向移植到 3.9 维护版本中。

增加了 Shell 侧栏。 将主提示符(“>>>”)移至侧栏。二级提示符(“…”)也加入侧栏。在编辑器的行号侧栏上鼠标单击和可选的拖动,会选定一行或多行文本。在选定文本行后右击将显示包含“copy with prompts”的上下文菜单。这会将侧栏的提示符与选定文本行合并。该选项也会在文本的上下文菜单中显示。(由 Tal Einat 在 bpo-37903 [https://bugs.python.org/issue?@action=redirect&bpo=37903] 中贡献)

使用空格而不是制表符来缩进交互式代码。 这使得交互式代码条目 "看起来很正确"。 使之可行是增加 shell 侧边栏的一个主要动机。 (由 Terry Jan Reedy 在 bpo-37892 [https://bugs.python.org/issue?@action=redirect&bpo=37892] 中贡献。)

在模式匹配语句中高亮显示新的 软关键字 matchcase_。 但这种高亮显示并不完美,某些极端情况下还会出现错误,包括 case 模式中的一些 _。 (由 Tal Einat 在 bpo-44010 [https://bugs.python.org/issue?@action=redirect&bpo=44010] 中贡献。)

3.10 维护版本中的新内容。

.pyi 文件应用语法高亮。 (由 Alex Waygood 和 Terry Jan Reedy 在 bpo-45447 [https://bugs.python.org/issue?@action=redirect&bpo=45447] 中贡献。)

当附带输入和输出地保存 Shell 时将包括提示符。 (由 Terry Jan Reedy 在 gh-95191 [https://github.com/python/cpython/issues/95191] 中贡献。)

importlib.metadata

importlib_metadata 4.6(history [https://importlib-metadata.readthedocs.io/en/latest/history.html])的功能一致。

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

增加了 importlib.metadata.packages_distributions() 用于将最高层级 Python 模块和包解析为其 importlib.metadata.Distribution

inspect

若模块中没有定义 __loader__ ,则回退至使用 __spec__.loader 。(由 Brett Cannon 在 bpo-42133 [https://bugs.python.org/issue?@action=redirect&bpo=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 在 bpo-43817 [https://bugs.python.org/issue?@action=redirect&bpo=43817] 中贡献。)

itertools

添加了 itertools.pairwise()。 (由 Raymond Hettinger 在 bpo-38200 [https://bugs.python.org/issue?@action=redirect&bpo=38200] 中贡献。)

linecache

若模块中没有定义 __loader__ ,则回退至使用 __spec__.loader 。(由 Brett Cannon 在 bpo-42133 [https://bugs.python.org/issue?@action=redirect&bpo=42133] 中贡献)

os

为 VxWorks 实时操作系统增加 os.cpu_count() 支持。 (由 Peixing Xin 在 bpo-41440 [https://bugs.python.org/issue?@action=redirect&bpo=41440] 中贡献。)

加入一个新函数 os.eventfd() 及其助手函数,以封装 Linux 的系统调用 eventfd2 。(由 Christian Heimes 在 bpo-41001 [https://bugs.python.org/issue?@action=redirect&bpo=41001] 中贡献)

增加 os.splice() 以允许在两个文件描述符之间移动数据,而无需在内核地址空间和用户地址空间之间进行复制,其中一个文件描述符必须指向某个管道。 (由 Pablo Galindo 在 bpo-41625 [https://bugs.python.org/issue?@action=redirect&bpo=41625] 中贡献。)

为 macOS 增加了 O_EVTONLY, O_FSYNC, O_SYMLINKO_NOFOLLOW_ANY。 (由 Donghee Na 在 bpo-43106 [https://bugs.python.org/issue?@action=redirect&bpo=43106] 中贡献。)

os.path

现在 os.path.realpath() 可接受一个关键字参数 strict。 若设为 True ,则在路径不存在或遭遇循环符号链接时,会触发 OSError。 (由 Barney Gale 在 bpo-43757 [https://bugs.python.org/issue?@action=redirect&bpo=43757] 中贡献。)

pathlib

PurePath.parents 增加切片支持。 (由 Joshua Cannon 在 bpo-35498 [https://bugs.python.org/issue?@action=redirect&bpo=35498] 中贡献。)

PurePath.parents 增加负序列号支持。 (由 Yaroslav Pankovych 在 bpo-21041 [https://bugs.python.org/issue?@action=redirect&bpo=21041] 中贡献。)

增加了 Path.hardlink_to 方法来取代 link_to()。 这个新方法的参数顺序与 symlink_to() 的相同。 (由 Barney Gale 在 bpo-39950 [https://bugs.python.org/issue?@action=redirect&bpo=39950] 中贡献。)

现在 pathlib.Path.stat()chmod() 接受一个关键字参数 follow_symlinks ,以便与 os 模块中的对应函数保持一致。(由 Barney Gale 贡献于 bpo-39906 [https://bugs.python.org/issue?@action=redirect&bpo=39906] )

平台

增加 platform.freedesktop_os_release() 用于从 freedesktop.org os-release [https://www.freedesktop.org/software/systemd/man/os-release.html] 标准文件提取操作系统标识。 (由 Christian Heimes 在 bpo-28468 [https://bugs.python.org/issue?@action=redirect&bpo=28468] 中贡献。)

pprint

现在 pprint.pprint() 接受一个新的关键字参数 underscore_numbers。(由 sblondon 贡献于 bpo-42914 [https://bugs.python.org/issue?@action=redirect&bpo=42914] )

现在 pprint 可以完美打印 dataclasses.dataclass 实例。(由 Lewis Gaul 贡献于 bpo-43080 [https://bugs.python.org/issue?@action=redirect&bpo=43080] )

py_compile

py_compile' 的命令行界面加入 `—quiet`` 选项。(由 Gregory Schevchenko 贡献于 bpo-38731 [https://bugs.python.org/issue?@action=redirect&bpo=38731] )

pyclbr

pyclbr.readmodule()pyclbr.readmodule_ex() 返回的结果树中的 FunctionClass 对象上添加一个 end_lineno 属性。 它将匹配现有的 (起始) lineno。 (由 Aviral Srivastava 在 bpo-38307 [https://bugs.python.org/issue?@action=redirect&bpo=38307] 中贡献。)

shelve

现在 shelve 在创建 shelve 时默认使用 pickle.DEFAULT_PROTOCOL 而不是 pickle 协议 3。 (由 Zackery Spytz 在 bpo-34204 [https://bugs.python.org/issue?@action=redirect&bpo=34204] 中贡献。)

statistics

加入 covariance() 、Pearson 的 correlation() 和简单的 linear_regression() 函数。(由 Tymoteusz Wołodźko 贡献于 bpo-38490 [https://bugs.python.org/issue?@action=redirect&bpo=38490] )

site

若模块中没有定义 __loader__ ,则回退至使用 __spec__.loader 。(由 Brett Cannon 在 bpo-42133 [https://bugs.python.org/issue?@action=redirect&bpo=42133] 中贡献)

socket

现在异常 socket.timeoutTimeoutError 的别名。(由 Christian Heimes 在 bpo-42413 [https://bugs.python.org/issue?@action=redirect&bpo=42413] 中贡献。)

加入用 IPPROTO_MPTCP 创建 MPTCP 套接字的选项(由 Rui Cunha 贡献于 bpo-43571 [https://bugs.python.org/issue?@action=redirect&bpo=43571] )

加入 IP_RECVTOS 选项,以便接收服务类型(ToS)或 DSCP/ECN 字段(由 Georg Sauthoff 贡献于 bpo-44077 [https://bugs.python.org/issue?@action=redirect&bpo=44077] )

ssl

ssl 模块要求 OpenSSL 1.1.1 或更新版本。 (由 Christian Heimes 在 PEP 644 [https://peps.python.org/pep-0644/] 和 bpo-43669 [https://bugs.python.org/issue?@action=redirect&bpo=43669] 中贡献。)

ssl 模块已初步支持 OpenSSL 3.0.0 和新选项 OP_IGNORE_UNEXPECTED_EOF。 (由 Christian Heimes 在 bpo-38820 [https://bugs.python.org/issue?@action=redirect&bpo=38820], bpo-43794 [https://bugs.python.org/issue?@action=redirect&bpo=43794], bpo-43788 [https://bugs.python.org/issue?@action=redirect&bpo=43788], bpo-43791 [https://bugs.python.org/issue?@action=redirect&bpo=43791], bpo-43799 [https://bugs.python.org/issue?@action=redirect&bpo=43799], bpo-43920 [https://bugs.python.org/issue?@action=redirect&bpo=43920], bpo-43789 [https://bugs.python.org/issue?@action=redirect&bpo=43789] 和 bpo-43811 [https://bugs.python.org/issue?@action=redirect&bpo=43811] 中贡献。)

现在,已弃用函数和使用已弃用常量会导致 DeprecationWarningssl.SSLContext.options 默认设置了 OP_NO_SSLv2OP_NO_SSLv3 ,因而设置此标记无法再次发出警告了。 弃用部分 列出了已弃用的特性。 (由 Christian Heimes 贡献于 bpo-43880 [https://bugs.python.org/issue?@action=redirect&bpo=43880] )

现在,ssl 模块默认设置的安全性提高了。默认情况下,不具备前向安全性或 SHA-1 MAC 的加密算法会被禁用。二级安全禁止安全性低于 112 位的弱 RSA、DH 和 ECC 密钥。 SSLContext 默认的最低版本协议为 TLS 1.2。这些设置是基于 Hynek Schlawack 的研究。(由 Christian Heimes 贡献于 bpo-43998 [https://bugs.python.org/issue?@action=redirect&bpo=43998] )

已弃用的协议 SSL 3.0, TLS 1.0 和 TLS 1.1 不再受到官方支持。Python 不会直接禁用。但 OpenSSL 编译选项、发行版配置、厂商补丁和加密套件可能会阻止握手成功。

ssl.get_server_certificate() 函数加入 timeout 形参。(由 Zackery Spytz 贡献于 bpo-31870 [https://bugs.python.org/issue?@action=redirect&bpo=31870] )

ssl 模块用到了堆类型和多阶段初始化。(由 Christian Heimes 贡献于 bpo-42333 [https://bugs.python.org/issue?@action=redirect&bpo=42333] )

增加了一个新的校验旗标 VERIFY_X509_PARTIAL_CHAIN。 (由 l0x 在 bpo-40849 [https://bugs.python.org/issue?@action=redirect&bpo=40849] 中贡献。)

sqlite3

connect/handle()enable_load_extension()load_extension() 加入审计事件。(由 Erlend E. Aasland 贡献于 bpo-43762 [https://bugs.python.org/issue?@action=redirect&bpo=43762])

sys

加入了 sys.orig_argv 属性:传给 Python 可执行文件的初始命令行参数列表。(由 Victor Stinner 贡献于 bpo-23427 [https://bugs.python.org/issue?@action=redirect&bpo=23427] )

添加了 sys.stdlib_module_names,包含标准库模块名称的列表。 (由 Victor Stinner 在 bpo-42955 [https://bugs.python.org/issue?@action=redirect&bpo=42955] 中贡献。)

_thread

现在 _thread.interrupt_main() 接受一个可选的信号数值供模拟 (默认值仍为 signal.SIGINT)。 (由 Antoine Pitrou 在 bpo-43356 [https://bugs.python.org/issue?@action=redirect&bpo=43356] 中贡献。)

threading

加入 threading.gettrace()threading.getprofile() ,分别用于获取 threading.settrace()threading.setprofile() 设置的函数。(由Mario Corchero 贡献于 bpo-42251 [https://bugs.python.org/issue?@action=redirect&bpo=42251] )

加入 threading.__excepthook__ ,用于获取 threading.excepthook() 的初始值,以防被设为一个差劲或其他的值。(由 Mario Corchero 贡献于 bpo-42308 [https://bugs.python.org/issue?@action=redirect&bpo=42308] )

traceback

现在,format_exception()format_exception_only()print_exception() 函数可以接受一个异常对象,作为唯一的位置参数。(由 Zackery Spytz 和 Matthias Bussonnier 贡献于 bpo-26389 [https://bugs.python.org/issue?@action=redirect&bpo=26389])

types

重新引入 types.EllipsisTypetypes.NoneTypetypes.NotImplementedType 类,以提供一套新的类型,可供类型检查程序解释。(由 Bas van Beek 贡献于 bpo-41810 [https://bugs.python.org/issue?@action=redirect&bpo=41810])

typing

主要的变化参阅 有关类型提示的新增特性

typing.Literal 的行为被改为遵循 PEP 586 [https://peps.python.org/pep-0586/] 并匹配该 PEP 所描述的静态类型检查器的行为。

  • Literal 现在将是去重后的形参。

  • Literal 对象的相等性比较现在将与顺序无关。

  • Literal 比较现在会考虑类型。 例如 Literal[0] == Literal[False] 之前的结果值为 True。 现在则为 False。 为支持此改变,内部使用的类型缓存现在也支持区分类型。

  • 现在,如果 Literal 对象的任何参数都不是 hashable ,在相等性比较时将引发 TypeError 异常。请注意,在声明 Literal 时,参数不可哈希不会抛出错误:

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

(由 Yurii Karabas 在 bpo-42345 [https://bugs.python.org/issue?@action=redirect&bpo=42345] 中贡献。)

加入新函数 typing.is_typeddict() 用于内部检查标注是否为 typing.TypedDict。 (由 Patrick Reader 在 bpo-41792 [https://bugs.python.org/issue?@action=redirect&bpo=41792] 中贡献。)

只声明了数据变量的 typing.Protocol 子类在使用 isinstance 进行检查时现在将引发 TypeError,除非它们是带有 runtime_checkable() 装饰器的。 在之前版本中,这些检查会静默地通过。 如果用户需要运行时协议则应当对其子类设置 runtime_checkable() 装饰器。 (由 Yurii Karabas 在 bpo-38908 [https://bugs.python.org/issue?@action=redirect&bpo=38908] 中贡献。)

typing.iotyping.re 子模块导入现在将发出 DeprecationWarning。 这些子模块从 Python 3.8 开始已被弃用并将在未来的某个 Python 版本中被移除。 任何属于这些子模块的东西都应当改为直接从 typing 导入。 (由 Sebastian Rittau 在 bpo-38291 [https://bugs.python.org/issue?@action=redirect&bpo=38291] 中贡献。)

unittest

加入新方法 assertNoLogs() ,以补充现有的 assertLogs()。(由 Kit Yan Choi 贡献于 bpo-39385 [https://bugs.python.org/issue?@action=redirect&bpo=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 在 bpo-42967 [https://bugs.python.org/issue?@action=redirect&bpo=42967] 中贡献。)

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

xml

xml.sax.handler 模块中加入一个 LexicalHandler 类。(由 Jonathan Gossage 和 Zackery Spytz 贡献于 bpo-35018 [https://bugs.python.org/issue?@action=redirect&bpo=35018] )

zipimport

加入 PEP 451 [https://peps.python.org/pep-0451/] 相关的方法: find_spec()zipimport.zipimporter.create_module()zipimport.zipimporter.exec_module()。(由 Brett Cannon 贡献于 bpo-42131 [https://bugs.python.org/issue?@action=redirect&bpo=42131] )

加入 invalidate_caches() 方法。(由 Desmond Cheong 贡献于 bpo-14678 [https://bugs.python.org/issue?@action=redirect&bpo=14678] )

性能优化

弃用

(由 Jelle Zijlstra 在 gh-87889 [https://github.com/python/cpython/issues/87889] 中贡献。)

移除

  • 这简化了高层级 API。

  • 高层级 API 中的这些函数自 Python 3.7 起已经会隐式地获取当前线程正在运行的事件循环。 在大多数正常使用场景中都没有必要向 API 传入事件循环。

  • 在处理不同线程中运行的事件循环时传递事件循环特别容易产生错误。

请注意低层级 API 仍将接受 loop。 请参阅 Python API 的变化 来获取有关如何替换现有代码的示例。

(由 Yurii Karabas, Andrew Svetlov, Yury Selivanov 和 Kyle Stanley 在 bpo-42392 [https://bugs.python.org/issue?@action=redirect&bpo=42392] 中贡献。)

移植到 Python 3.10

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

Python 语法中的变化

  • 现在当编译之前有效的语法时如果数字类字面值后面紧跟一个关键字(如在 0in x 中)则会发出弃用警告。 在未来的版本中它将被改为语法警告,最终会改为语法错误。 要避免警告并使代码与未来的版本保持兼容只需在数字和后面的关键字之间添加一个空格。 (由 Serhiy Storchaka 在 bpo-43833 [https://bugs.python.org/issue?@action=redirect&bpo=43833] 中贡献。)

Python API 的变化

现在如下协程:

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

应替换为:

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

如果 foo() 被特别设计成 不 运行于当前线程的运行事件循环中(比如运行在另一个线程的事件循环中),请考虑使用 asyncio.run_coroutine_threadsafe() 来代替。

(由 Yurii Karabas, Andrew Svetlov, Yury Selivanov 和 Kyle Stanley 在 bpo-42392 [https://bugs.python.org/issue?@action=redirect&bpo=42392] 中贡献。)

C API 的变化

  • 由于换成了新的 PEG 解析程序,C 语言 API 函数 PyParser_SimpleParseStringFlagsPyParser_SimpleParseStringFlagsFilenamePyParser_SimpleParseFileFlagsPyNode_Compile 以及这些函数用到的类型 struct _node 已被删除。

现在应该用 Py_CompileString() 将源代码直接编译为代码对象。然后可以用 PyEval_EvalCode() 之类的东西来对其求值。

特别地:

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

CPython 字节码的改变

编译版的变化

某些 Linux 发行版的打包策略建议不要绑定依赖关系。比如 Fedora 在 usrshare/python-wheels/ 目录下安装 wheel 包,而不安装 ensurepip._bundled 包。

(由 Victor Stinner 贡献于 bpo-42856 [https://bugs.python.org/issue?@action=redirect&bpo=42856])

(由 Victor Stinner 在 bpo-43103 [https://bugs.python.org/issue?@action=redirect&bpo=43103] 中贡献。)

C API 的变化

PEP 652:稳定版 ABI 的维护

现在,用于扩展模块或嵌入 Python 的稳定版 ABI (应用程序二进制接口)已有显式的定义。 C API 的稳定性 描述了 C API 和 ABI 稳定性保证和稳定版 ABI 的最佳实践。

(由 Petr Viktorin 在 PEP 652 [https://peps.python.org/pep-0652/] 和 bpo-43795 [https://bugs.python.org/issue?@action=redirect&bpo=43795] 中贡献。).)

新的特性

--with-trace-refs 特殊编译方式下(Py_TRACE_REFS 宏),仍不支持使用受限 C API 。(由 Victor Stinner 贡献于 bpo-43688 [https://bugs.python.org/issue?@action=redirect&bpo=43688] )

移植到 Python 3.10

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

(由 Victor Stinner 在 bpo-39573 [https://bugs.python.org/issue?@action=redirect&bpo=39573] 中贡献。)

弃用

移除

Py_SymtableString() 函数误为稳定版 ABI 却无法使用,因为 symtable.h 头文件不属于受限 C API。

请改用 Python symtable 模块。 (由 Victor Stinner 在 bpo-43244 [https://bugs.python.org/issue?@action=redirect&bpo=43244] 中贡献。)

  • PyOS_ReadlineFunctionPointer() 已从受限 C API 头文件和 python3.dll 中移除,此 dll 为 Windows 中的稳定版 ABI 库。由于该函数可接受一个 FILE* 参数,所以无法保证其 ABI 稳定性。(由 Petr Viktorin 贡献于 bpo-43868 [https://bugs.python.org/issue?@action=redirect&bpo=43868] )

  • 移除了 ast.h, asdl.hPython-ast.h 头文件。 这些函数未入文档且不属于受限 C API。这些头文件中定义的大多数名称都不带 Py 前缀,因此可能会造成命名冲突。比如 Python-ast.h 定义了一个 Yield 宏,就会与另一个Windows 头文件中的 Yield 冲突。请改用 Python ast 模块。(由 Victor Stinner 贡献于 bpo-43244 [https://bugs.python.org/issue?@action=redirect&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 [https://bugs.python.org/issue?@action=redirect&bpo=43244] )

  • 移除了包含下列函数的头文件 pyarena.h

    • PyArena_New()

    • PyArena_Free()

    • PyArena_Malloc()

    • PyArena_AddPyObject()

这些函数未记入文档,且不属于受限 C API,仅由编译器内部使用。(由 Victor Stinner 贡献于 bpo-43244 [https://bugs.python.org/issue?@action=redirect&bpo=43244] )

3.10.7 中的重要安全特性

使用 2 (二进制), 4, 8 (八进制), 16 (十六进制) 或 32 以外的基数例如以 10 (十进制) 为基数在 intstr 之间进行转换现在如果字符串表示形式中的位数超过特定限制则会引发 ValueError 以避免因算法复杂度导致的拒绝服务攻击风险。 这是对于 CVE 2020-10735 [https://www.cve.org/CVERecord?id=CVE-2020-10735] 的一种缓解方案。 此限制可通过环境变量、命令行旗标或 sys API 来配置或者禁用。 参见 整数字符串转换长度限制 文档。 字符串形式的默认限制为 4300 位数字。

3.10.8 中的重要安全特性

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

3.10.12 中的重要变化

tarfile