
这篇文章旨在快速介绍Python每个新版本所带来的主要变化。这有助于你在升级代码库时利用新特性,或者确保你有适当的防护措施以兼容旧版本。
这篇内容分为两个部分:第一部分介绍实际的变化,第二部分介绍有助于升级代码库的实用工具、链接和程序。
版本
在本节中,我记录了Python语法和标准库的主要变化。除了typing模块外,我基本排除了其他模块的变化。我没有包含任何关于C-API、字节码或其他底层部分的变化。
对于每个部分,终止支持日期(EOL)指的是Python软件基金会将不再为特定版本提供安全补丁的日期。
Python 3.7及更早版本(2023年6月停止支持)
本节已合并,因为在撰写本文时,所有这些版本都已停止支持,但如果你已经用Python编程有一段时间了,可能已经忘记这些功能是何时引入的了。
- async 和 await(3.5+)
- 矩阵运算符:a @ b(3.5+)
- 类型提示(3.5+)
- 格式化字符串字面值(又名f-字符串)
f"{something}"(3.6及以上版本) - 数字字面量中的下划线
1_000_000(3.6+) - 字典保证插入顺序(3.7+)
- contextvars(3.7+)
- dataclasses(3.7+)
- importlib.resources(3.7+)
from __future__ import annotations(3.7+,在3.14中被取代)
Python 3.8(生命周期结束 2024年10月)
-
赋值表达式
也被称为海象运算符pythonif (thing := get_thing()) is not None: do_something(thing) else: raise Exception(f"Something is wrong with {thing}") -
仅位置参数
pythondef foo(a, b, /, c, d, *, e, f): # a, b: positional only # c, d: positional or keyword # e, f: keyword only -
自文档化f-字符串
python# Before f"user={user}" # Now f"{user=}" -
导入库元数据
pythonimport importlib.metadata importlib.metadata.version("some-library") # "2.3.4" importlib.metadata.requires("some-library") # ["thing==1.2.4", "other>=5"] importlib.metadata.files("some-library") # [...] -
类型标注 :TypedDict、Literal、Final、Protocol
- TypedDict - PEP 589
- Literal - PEP 586
- Final - PEP 591
- Protocol - PEP 544
Python 3.9(终止支持 2025年10月)
-
类型标注:内置泛型
现在可以使用dict[...]、list[...]、set[...]等,而不是使用typing.Dict, List, Set。 -
移除前缀/后缀
字符串及类似类型现在可以使用removeprefix和removesuffix更安全地从开头或结尾移除内容。这比字符串切片方法更安全,因为切片方法依赖于正确计算前缀的长度(并且要记住在前缀发生变化时修改切片)。pythonsection = header.removeprefix("X-Forwarded-") -
字典联合运算符(PEP 584)
pythoncombined_dict = dict_one | dict_two updated_dict |= dict_three -
注解(PEP 593)
pythonmy_int: Annotated[int, SomeRange(0, 255)] = 0 -
Zoneinfo(PEP 615)
IANA时区数据库现已成为标准库的一部分pythonimport zoneinfo some_zone = zoneinfo.ZoneInfo("Europe/Berlin")对于早期的Python版本,可以通过PyPI获取:
backports.zoneinfo。
Python 3.10(终止支持 2026年10月)
-
结构化模式匹配(PEP 634、PEP 635、PEP 636)
参见变更日志以获取更多示例。pythonmatch command.split(): case ["quit"]: print("Goodbye!") quit_game() case ["look"]: current_room.describe() case ["get", obj]: character.get(obj, current_room) case ["go", direction]: current_room = current_room.neighbor(direction) case [action]: ... # interpret single-verb action case [action, obj]: ... # interpret action, obj case _: ... # anything that didn't match -
类型标注:使用竖线的联合类型
python# Before from typing import Optional, Union thing: Optional[Union[str, list[str]]] = None # Now thing: str | list[str] | None = None -
类型标注:ParamSpec(PEP 612)
在处理Callable和其他类似类型时,能够更好地传递类型信息。pythonfrom typing import Awaitable, Callable, ParamSpec, TypeVar P = ParamSpec("P") R = TypeVar("R") def add_logging(f: Callable[P, R]) -> Callable[P, Awaitable[R]]: async def inner(*args: P.args, **kwargs: P.kwargs) -> R: await log_to_database() return f(*args, **kwargs) return inner @add_logging def takes_int_str(x: int, y: str) -> int: return x + 7 await takes_int_str(1, "A") # Accepted await takes_int_str("B", 2) # Correctly rejected by the type checker -
类型标注:TypeAlias(PEP 613)
pythonStrCache: TypeAlias = 'Cache[str]' # a type alias LOG_PREFIX = 'LOG[DEBUG]' # a module constant -
类型标注:TypeGuard(PEP 647)
python_T = TypeVar("_T") def is_two_element_tuple(val: Tuple[_T, ...]) -> TypeGuard[Tuple[_T, _T]]: return len(val) == 2 def func(names: Tuple[str, ...]): if is_two_element_tuple(names): reveal_type(names) # Tuple[str, str] else: reveal_type(names) # Tuple[str, ...] -
带括号的上下文管理器(PEP 617)
pythonwith (CtxManager() as example): ... with ( CtxManager1(), CtxManager2() ): ... with (CtxManager1() as example, CtxManager2()): ... with (CtxManager1(), CtxManager2() as example): ... with ( CtxManager1() as example1, CtxManager2() as example2, ): ... -
数据类:slots、kw_only
数据类装饰器现在支持以下功能:kw_only=True则__init__中的所有参数都将被标记为仅限关键字参数。slots=True生成的数据类将使用__slots__来存储数据。
Python 3.11(生命周期结束 2027年10月)
-
Tomllib
tomllib - 标准库TOML解析器
-
异常组(PEP 654)
PEP 654引入了一些语言特性,使程序能够同时引发和处理多个不相关的异常。内置类型
ExceptionGroup和BaseExceptionGroup使得对异常进行分组并一起引发成为可能,而新的except*语法则对except进行了扩展,以匹配异常组的子组。 -
用注释丰富异常(PEP 678)
add_note()方法被添加到BaseException中。它可用于为异常添加在异常抛出时无法获取的上下文信息。添加的注释会出现在默认的回溯中。pythontry: do_something() except BaseException as e: e.add_note("this happened during do_something") raise -
类型提示:Self(PEP 673)
pythonclass MyClass: @classmethod def from_hex(cls, s: str) -> Self: # Self means instance of cls return cls(int(s, 16)) def frobble(self, x: int) -> Self: # Self means this instance self.y >> x return self -
类型标注:LiteralString(PEP 675)
新的
LiteralString注解可用于表明函数参数可以是任何字面量字符串类型。这使得函数能够接受任意的字面量字符串类型,以及由其他字面量字符串创建的字符串。这样,类型检查器就可以确保像执行SQL语句或shell命令这类敏感函数只能通过静态参数调用,从而提供针对注入攻击的保护。 -
类型提示:将TypedDict条目标记为[非]必需项(PEP 655)
python# default is required class Movie(TypedDict): title: str year: NotRequired[int] # default is not-required class Movie(TypedDict, total=False): title: Required[str] year: int -
类型提示:通过TypeVarTuple实现可变参数泛型(PEP 646)
PEP 484 之前引入了 TypeVar,支持创建用单一类型参数化的泛型。PEP 646 新增了 TypeVarTuple,支持用任意数量的类型进行参数化。换句话说,TypeVarTuple 是一种可变类型变量,支持可变泛型。
这实现了各种各样的用例。特别是,它允许NumPy和TensorFlow等数值计算库中的类数组结构通过数组形状进行参数化。静态类型检查器现在能够捕获使用这些库的代码中与形状相关的错误。
-
类型标注:@dataclass_transform(PEP 681)
dataclass_transform可用于修饰类、元类或本身是装饰器的函数。@dataclass_transform()的存在会告知静态类型检查器,被修饰的对象会执行运行时"魔术"来转换类,使其具有dataclass般的行为。python# The create_model decorator is defined by a library. @typing.dataclass_transform() def create_model(cls: Type[T]) -> Type[T]: cls.__init__ = ... cls.__eq__ = ... cls.__ne__ = ... return cls # The create_model decorator can now be used to create new model classes: @create_model class CustomerModel: id: int name: str -
星号解包表达式允许用于for语句中
这是官方支持的语法
pythonfor x in *a, *b: print(x)
Python 3.12(终止支持时间:2028年10月)
-
类型标注:类型参数语法(PEP 695)
泛型类和函数的简洁注解
pythondef max[T](args: Iterable[T]) -> T: ... class list[T]: def __getitem__(self, index: int, /) -> T: ... def append(self, element: T) -> None: ... -
能够使用type语句声明类型别名(生成TypeAliasType)
pythontype Point = tuple[float, float] # Type aliases can also be generic type Point[T] = tuple[T, T] -
F字符串的变化(PEP 701)
f字符串中的表达式组件现在可以是任何有效的Python表达式,包括与包含该f字符串使用相同引号的字符串、多行表达式、注释、反斜杠和Unicode转义序列。
python## Can re-use quotes f"This is the playlist: {", ".join(songs)}" f"{f"{f"{f"{f"{f"{1+1}"}"}"}"}"}" # '2' ## Multiline f-string with comments f"This is the playlist: {", ".join([ 'Take me back to Eden', # My, my, those eyes like fire 'Alkaline', # Not acid nor alkaline 'Ascensionism' # Take to the broken skies at last ])}" ## Backslashes / Unicode f"This is the playlist: {"\n".join(songs)}" f"This is the playlist: {"\N{BLACK HEART SUIT}".join(songs)}" -
缓冲区协议(PEP 688)
PEP 688 引入了一种从 Python 代码中使用 缓冲区协议 的方法。实现了
__buffer__()方法的类现在可用作缓冲区类型。新的
collections.abc.BufferABC提供了一种表示缓冲区对象的标准方式,例如在类型注解中。新的inspect.BufferFlags枚举表示可用于自定义缓冲区创建的标志。 -
类型提示:用于kwargs类型提示的Unpack(PEP 692)
pythonfrom typing import TypedDict, Unpack class Movie(TypedDict): name: str year: int def foo(**kwargs: Unpack[Movie]): ... -
类型提示:override 装饰器(PEP 698)
确保子类重写的方法确实存在于父类中。
pythonfrom typing import override class Base: def get_color(self) -> str: return "blue" class GoodChild(Base): @override # ok: overrides Base.get_color def get_color(self) -> str: return "yellow" class BadChild(Base): @override # type checker error: does not override Base.get_color def get_colour(self) -> str: return "red"注意:这与
@overload装饰器不同。
Python 3.13(终止支持时间:2029年10月)
虽然这个Python版本没有包含很多新的语言特性,但它确实有一个相当长的变更日志,其中包含了对标准库的许多更改(包括移除某些内容)、更多受支持的平台(iOS和Android)、为locals()定义的语义以及一个改进后的交互式解释器。
-
自由线程(PEP 703)、即时编译(PEP 744)
虽然这并非语言层面的变更,但对大多数人而言,这是一个具有头条新闻价值的变化。
CPython 3.13 具备无需全局解释器锁(GIL)运行或使用即时编译器(JIT compiler)运行的能力。
-
static_attributes(静态属性)
存储通过类体中任何函数内的
self.<name>访问的属性名称。pythonclass A: def __init__(self, x: int, y: int): self.items = [x,y] self.max = max(x, y) return # A.__static_attributes__ = ("items", "max") -
文档字符串:常见的前导空白已去除
pythondef spam(): """ This is a docstring with leading whitespace. It even has multiple paragraphs! """ # ^^^^ This white space is stripped # spam.__doc__ = '\nThis is a docstring with\n leading whitespace.\n\nIt even has multiple paragraphs!\n' -
类型标注:类型参数默认值(PEP 696)
允许为
TypeVar、ParamSpec、TypeVarTuple设置默认值。更多示例请参见PEP。pythonDefaultBoolT = TypeVar("DefaultBoolT", default=bool) T = TypeVar("T") class OneDefault(Generic[T, DefaultBoolT]): ... OneDefault[float] == OneDefault[float, bool] # Valid -
类型提示:warnings支持类型弃用(PEP 702)
warnings模块中新增了一个新的装饰器@deprecated()。这个装饰器可用于类、函数或方法,以标记它们为已过时。这包括typing.TypedDict和typing.NamedTuple的定义。对于重载函数,该装饰器可应用于各个重载,表明特定的重载已过时。该装饰器也可应用于重载实现函数,表明整个函数已过时。 -
类型提示:TypedDict ReadOnly(PEP 705)
类型限定符
typing.ReadOnly用于表示在TypedDict定义中声明的项不得被修改(添加、修改或删除):pythonclass Band(TypedDict): name: str members: ReadOnly[list[str]] blur: Band = {"name": "blur", "members": []} blur["name"] = "Blur" # OK: "name" is not read-only blur["members"] = ["Damon Albarn"] # Type check error: "members" is read-only blur["members"].append("Damon Albarn") # OK: list is mutable -
类型标注:TypeIs(PEP 742)
TypeGuard的替代方案,用于对执行类型收窄的函数进行注解。
TypeIs和TypeGuard在以下方面有所不同:
- TypeIs要求缩小后的类型是输入类型的子类型,而TypeGuard则不要求。主要原因是为了允许将
list[object]缩小为list[str]之类的操作,尽管后者并不是前者的子类型,因为list是不变的。 - 当TypeGuard函数返回True时,类型检查器会将变量的类型精确地收窄为TypeGuard类型。当TypeIs函数返回True时,类型检查器可以结合变量先前已知的类型和TypeIs类型,推断出更精确的类型。(从技术上讲,这被称为交集类型。)
- 当TypeGuard函数返回False时,类型检查器完全无法缩小变量的类型范围。当TypeIs函数返回False时,类型检查器可以缩小变量的类型范围,以排除TypeIs类型。
pythonclass Parent: ... class Child(Parent): ... class Unrelated: ... def is_parent(val: object) -> TypeIs[Parent]: return isinstance(val, Parent) def run(arg: Child | Unrelated): if is_parent(arg): # Type of ``arg`` is narrowed to the intersection # of ``Parent`` and ``Child``, which is equivalent to # ``Child``. assert_type(arg, Child) else: # Type of ``arg`` is narrowed to exclude ``Parent``, # so only ``Unrelated`` is left. assert_type(arg, Unrelated) - TypeIs要求缩小后的类型是输入类型的子类型,而TypeGuard则不要求。主要原因是为了允许将
Python 3.14(终止支持时间:2030年10月)
和往常一样,有一长串非语言方面的更改,因此建议您阅读发布说明。
-
模板字符串(PEP 750)
模板字符串字面量(t字符串)会生成Template对象,这些对象随后可以被单独操作。
pythonfrom string.templatelib import Template name = "World" template: Template = t"Hello {name}!" print(template.strings) ('Hello ', '!') print(template.values) ('World',) -
注解的延迟求值(PEP 649、PEP 749)
注解不再被立即计算,而是存储在专用的注解函数中。新添加的
annotationlib模块允许与这些函数进行交互。请注意,使用from __future__ import annotations会对此产生影响。这意味着从Python 3.14开始,对于使用前向引用的注解,你不再需要添加引号或使用future导入。
python## BEFORE # String Quoting class A: def some_func(self, *args) -> 'B | None': ... class B: ... # future import from __future__ import annotations class A: def some_func(self, *args) -> B | None: ... class B: ... ## PYTHON 3.14 class A: def some_func(self, *args) -> B | None: # Just Works (TM) ... class B: ... -
允许不带括号的except和except(PEP 758) *
现在,
except和except*表达式在存在多个异常类型且未使用as子句时,允许省略括号。例如,以下表达式现在是有效的:pythontry: connect_to_server() except TimeoutError, ConnectionRefusedError: print("Network issue encountered.") # The same applies to except* (for exception groups): try: connect_to_server() except* TimeoutError, ConnectionRefusedError: print("Network issue encountered.") -
其他变更
- 自由线程Python现已正式支持(但仍是可选的)。
- 现在有多个解释器可用,它们位于
concurrent.interpreters模块中。过去,这些解释器只能通过C语言API获取。 - 当
return、break或continue语句退出finally块时,编译器会发出SyntaxWarning。(PEP 765)