Python版本之间的主要变化总结

这篇文章旨在作为每个新版本 Python 引入的主要更改的快速参考。这可以帮助您在升级代码库时利用新功能,或者确保您拥有正确的保护措施以与旧版本兼容。

这篇文章有两个部分:第一部分介绍了实际的更改,第二部分介绍了可以帮助升级代码库的有用工具、链接和实用程序。

Python 3.7 及更早版本
本节已合并,因为在撰写本文时所有这些版本都已停产,但如果您已经使用 Python 编程了一段时间,您可能已经忘记了这些功能是何时引入的。

  • 异步和等待 (3.5+)
  • 矩阵运算符:a @ b(3.5+)
  • 类型提示 (3.5+)
  • f-strings f"{something}" (3.6+)
  • 数字文字中的下划线1_000_000(3.6+)
  • 字典保证插入有序(3.7+)
  • contextvars(3.7+)
  • dataclasses(3.7+)

Python 3.8(2024 年 10 月)
赋值表达式
也称为海象运算符

if (thing := get_thing()) is not None:
  do_something(thing)
else:
  raise Exception(f"Something is wrong with {thing}")

仅位置参数

def foo(a, b, /, c, d, *, e, f):
  # a, b: positional only
  # c, d: positional or keyword
  # e, f: keyword only

自记录 f 字符串

# Before
f"user={user}"

# Now
f
"{user=}"

导入库元数据

import 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更安全地从开头或结尾删除内容。这比字符串切片方法更安全,字符串切片方法依赖于正确计算前缀的长度(并记住在前缀更改时更改切片)。

if header.startswith("X-Forwarded-"):
  section = header.removeprefix(
"X-Forwarded-")


Dict Union操作符 ( PEP 584 )

combined_dict = dict_one | dict_two
updated_dict |= dict_three


注释(PEP 593

my_int: Annotated[int, SomeRange(0, 255)] = 0

区域信息 ( PEP 615 )
IANA 时区数据库现已成为标准库的一部分

import zoneinfo
some_zone = zoneinfo.ZoneInfo("Europe/Berlin")


Python 3.10(2026 年 10 月)
结构模式匹配(PEP 634PEP 635PEP 636

match 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


使用pipe管道的Union 

# Before
from typing import Optional, Union
thing: Optional[Union[str, list[str]]] = None

# Now
thing: str | list[str] | None = None

ParamSpec (PEP 612)
在使用 Callable 和其他类似类型时,可以更好地传递键入信息。

from 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)

StrCache: TypeAlias = 'Cache[str]'  # a type alias
LOG_PREFIX = 'LOG[DEBUG]'  # a module constant

TypeGuard (PEP 647)

_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)

with (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- 标准库 TOML 解析器

Exception Groups (PEP 654)

  • PEP 654 引入了一些语言特性,使程序能够同时引发和处理多个不相关的异常。内置的 ExceptionGroup 和 BaseExceptionGroup 类型可以将异常分组并一起引发,而新的 except* 语法则将 except 概括为与异常组的子组匹配。

用注释丰富例外 (PEP 678)
  • 在 BaseException 中添加了 add_note() 方法。该方法可用于为异常添加在异常发生时无法获得的上下文信息。添加的注释会显示在默认回溯中。

try:
  do_something()
except BaseException as e:
  e.add_note("this happened during do_something")
  raise

Self (PEP 673)

class 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)

# 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(),静态类型检查程序就会知道被装饰的对象在运行时会对类进行 "魔法 "转换,使其具有类似数据类的行为。

# 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 语句中允许使用星形符号解包表达式:

for x in *a, *b:
  print(x)


Python 3.12 (EOL Oct 2028)
类型 参数语法(PEP 695)

  • 通用类和函数的紧凑注释

def max[T](args: Iterable[T]) -> T:
  ...

class list[T]:
  def __getitem__(self, index: int, /) -> T:
    ...

  def append(self, element: T) -> None:
    ...

  • 使用类型语句(生成 TypeAliasType)声明类型别名的功能

type Point = tuple[float, float]

# Type aliases can also be generic
type Point[T] = tuple[T, T]

F-string  (PEP 701)

  • f-string 中的表达式组件现在可以是任何有效的 Python 表达式,包括与包含 f-string 的字符串重复使用相同引号的字符串、多行表达式、注释、反斜线和 unicode 转义序列。

可重复使用引号(包括嵌套 f 字符串语句)
## 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.Buffer ABC 提供了表示缓冲区对象的标准方法,例如在类型注解中。新的 inspect.BufferFlags 枚举表示可用于自定义缓冲区创建的标志。

**kwargs 类型用于解包(PEP 692)

from typing import TypedDict, Unpack

class Movie(TypedDict):
  name: str
  year: int

def foo(**kwargs: Unpack[Movie]):
  ...


override 装饰器(PEP 698)
确保子类重载的方法实际上存在于父类中。

from 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"