Skip to content

What’s New In Python 3.11

Python 3.11 is between 10-60% faster than Python 3.10. On average, we measured a 1.25x speedup on the standard benchmark suite. See Faster CPython for details.

  1. 总的来说, 有一些纯Python的性能优化比较明显
  2. 异步调度也更加友好了

Important

PEP 678: Exceptions can be enriched with notes

通过add_note 方法为BaseEexception添加上下文相关的注释.

Example
try:
    raise TypeError('bad type')
except Exception as e:
    e.add_note('Add some information')
    raise

asyncio

TaskGroup

Added cancelling() and uncancel() methods to Task. These are primarily intended for internal use, notably by TaskGroup.

通过异步上下文并发控制多个异步任务,并等待全部结束

Example
import asyncio

async def task1():
    await asyncio.sleep(1)
    print("task1 finished")
    return "result1"

async def task2():
    await asyncio.sleep(2)
    print("task2 finished")
    return "result2"

async def main():
    async with asyncio.TaskGroup() as tg:
        t1 = tg.create_task(task1())
        t2 = tg.create_task(task2())

    # 当退出async with时,TaskGroup已确保所有任务完成
    print(f"task1 result: {t1.result()}")
    print(f"task2 result: {t2.result()}")

asyncio.run(main())

timeout

使用asyncio.timeout上下文管理器代替asyncio.wait_for以控制超时调度

Example
import asyncio

async def long_running_task():
    await asyncio.sleep(5)
    return "task completed"

async def main():
    try:
        # 设置超时时间为3秒,超过时间未完成则抛出TimeoutError
        async with asyncio.timeout(3):
            result = await long_running_task()
            print(result)
    except TimeoutError:
        print("任务执行超时")

asyncio.run(main())

Runner

asyncio.Runner 允许在同一线程内多次调度异步协程代码, 避免重复创建/关闭事件循环带来的性能和安全隐患

Example
import asyncio

async def main():
    await asyncio.sleep(1)
    print("hello")

# 使用 Runner 作为上下文管理器,运行异步函数
with asyncio.Runner() as runner:
    runner.run(main())

Others

  1. Path.glob()Path.rglob() 路径参数以/结尾时, 只返回路径不返回文件

Nice

PEP 657: Fine-grained error locations in tracebacks

异常打印显示的错误颗粒度更细了

Example
Traceback (most recent call last):
  File "distance.py", line 11, in <module>
    print(manhattan_distance(p1, p2))
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "distance.py", line 6, in manhattan_distance
    return abs(point_1.x - point_2.x) + abs(point_1.y - point_2.y)
                           ^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'x'

Type Hints

PEP 646: Variadic generics

可变参数泛型注解, 允许定义泛型类接受任意数量和类型的类型参数

Example
from typing import Generic, TypeVar, TypeVarTuple

Ts = TypeVarTuple('Ts')

class Array(Generic[*Ts]):
    def __init__(self, *values: *Ts):
        self.values = values

    def add_dimension(self, value) -> 'Array[*Ts, type(value)]':
        return Array(*self.values, value)

a = Array[int, str](1, 'foo')
print(a.values)  # (1, 'foo')

b = a.add_dimension(3.14)
print(b.values)  # (1, 'foo', 3.14)

PEP 655: Marking individual TypedDict items as required or not-required

允许在 TypedDict 中单独为key 标记必需或可选

Example
from typing import TypedDict, NotRequired, Required

class Movie(TypedDict):
    title: Required[str]
    director: NotRequired[str]
    year: Required[int]
    rating: NotRequired[float]

movie1: Movie = {
    "title": "Inception",
    "year": 2010,
    # "director" 和 "rating" 可以省略
}

movie2: Movie = {
    "title": "The Matrix",
    "director": "The Wachowskis",
    "year": 1999,
    "rating": 8.7,
}

PEP 673: Self type

使用 typing.Self 注解返回值为该类的实例

Example
class MyLock:
    def __enter__(self) -> Self:
        self.lock()
        return self

    ...

class MyInt:
    @classmethod
    def fromhex(cls, s: str) -> Self:
        return cls(int(s, 16))

    ...

PEP 675: Arbitrary literal string type

typing.LiteralString 标注任意的字面量字符串类型

Example
def run_query(sql: LiteralString) -> ...
    ...

def caller(
    arbitrary_string: str,
    query_string: LiteralString,
    table_name: LiteralString,
) -> None:
    run_query("SELECT * FROM students")       # ok
    run_query(query_string)                   # ok
    run_query("SELECT * FROM " + table_name)  # ok
    run_query(arbitrary_string)               # type checker error
    run_query(                                # type checker error
        f"SELECT * FROM students WHERE name = {arbitrary_string}"
    )

asyncio

asyncio.StreamWriter.start_tls

Added the asyncio.StreamWriter.start_tls() method for upgrading existing stream-based connections to TLS. (Contributed by Ian Good in bpo-34975.)

enum

verify

为 Enum 类增加约束检查, 很方便

Example
from enum import Enum, verify, UNIQUE, CONTINUOUS, NAMED_FLAGS, Flag

# 检查枚举值唯一
@verify(UNIQUE)
class ColorUnique(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3
    # CRIMSON = 1  # 如果取消注释,会抛出 ValueError,提示有别名

# 检查枚举值连续
@verify(CONTINUOUS)
class ColorContinuous(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3
    # FOUR = 5  # 如果取消注释,会抛出 ValueError,提示缺少中间值 4

# 检查 Flag 枚举的组合值必须对应已命名的标志
@verify(NAMED_FLAGS)
class ColorFlags(Flag):
    RED = 1
    GREEN = 2
    BLUE = 4
    WHITE = 7  # 7是RED|GREEN|BLUE的组合,合法
    # INVALID = 8  # 如果取消注释,因组合值无对应命名标志,会抛出 ValueError

print(list(ColorUnique))
print(list(ColorContinuous))
print(list(ColorFlags))

member、nomember

允许为 Enum 添加方法作为成员/非成员属性

Example
from enum import Enum, member, nonmember

class Menu(Enum):
    NEW = "NewGame"
    LOAD = "LoadGame"

    @member
    @staticmethod
    def QUIT():
        return "QuitGame"

    @nonmember
    def helper(self):
        return f"Help for {self.name}"

# 访问枚举成员
print(Menu.NEW)
print(Menu.QUIT)

# helper 不会作为成员出现
print(hasattr(Menu, 'helper'))  # True
print('helper' in Menu.__members__)  # False
print(Menu.NEW.helper())  # 调用普通方法

peoperty

为枚举成员而不是枚举类本身添加计算属性, 避免和枚举成员名称冲突

Example
from enum import Enum, property

class Planet(Enum):
    MERCURY = 0.39
    VENUS = 0.72
    EARTH = 1.00

    @property
    def distance_au(self):
        # 返回距离太阳的天文单位(AU)
        return self.value

    @property
    def distance_km(self):
        # 根据AU换算公里,1 AU ≈ 1.496e8 km
        return self.value * 1.496e8

print(Planet.EARTH.distance_au)   # 输出: 1.0
print(Planet.EARTH.distance_km)   # 输出: 149600000.0

global_enum

  1. 将枚举类的成员提升到模块的属性
Example
from enum import global_enum, Enum
import cmath

@global_enum
class Constants(float, Enum):
    PI = cmath.pi
    E = cmath.e

print('PI' in globals())  # True
print('E' in globals())   # True

Flag

操作支持

enum.Flag 支持leninnot in 操作

Example
from enum import Flag, auto

class AFlag(Flag):
    ONE = auto()  # 1
    TWO = auto()  # 2
    FOUR = auto() # 4

combined = AFlag.ONE | AFlag.TWO  # 组合

print(len(combined))  # 输出 2,因为组合中包含两个标志成员
print(list(combined)) # 输出 [AFlag.ONE, AFlag.TWO]
print(AFlag.ONE in combined)  # True,检查成员是否包含
print(AFlag.FOUR in combined) # False
primary values and aliases

将 Flag 的成员分为主值和别名, 别名用主值的组合表现

Example
from enum import Flag, auto

class Color(Flag):
    RED = auto()    # 1
    GREEN = auto()  # 2
    BLUE = auto()   # 4
    WHITE = RED | GREEN | BLUE  # 7

print(list(Color))  
# 输出: [<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]
# WHITE 不在列表中,因为它是组合值,不是主值

print(~Color.RED)  
# 输出: <Color.GREEN|BLUE: 6>,取反得到正等价组合而非负值

Trivial

PEP654: Exception Groups and except*

支持嵌套的异常组并支持在捕获异常时提取组内的异常多次处理

Example
from builtins import ExceptionGroup

def test():
    raise ExceptionGroup(
        "Multiple errors",
        [
            ValueError("Invalid value"),
            ExceptionGroup(
                "Nested group",
                [
                    ImportError("No module found"),
                    ModuleNotFoundError("Another module missing")
                ]
            ),
            TypeError("Wrong type")
        ]
    )

try:
    test()
except* ValueError as e:
    print("Caught ValueError:", e)
except* ImportError as e:
    print("Caught ImportError:", e)
### indows py.exe launcher improvements > The copy of the Python Install Manager included with Python 3.11 has been significantly updated. It now supports company/tag syntax as defined in PEP 514 using the -V:/ argument instead of the limited -.. This allows launching distributions other than PythonCore, the one hosted on python.org.

Type Hints

PEP 681: Data class transforms

为静态类型检查器标识某个类支持数据类的特点, 以自动推断使用.

Example
from typing import dataclass_transform

@dataclass_transform()
def my_dataclass(cls):
    return cls

@my_dataclass
class Point:
    x: int
    y: int

p = Point()
p.x = 10
p.y = 20

print(p.x, p.y)
#### PEP 563 may not be the future PEP563 中对注解保存为字符串进行延迟求值的策略在未来可能搁置

asyncio

all_errors to the asyncio.loop.create_connection

Added keyword argument all_errors to asyncio.loop.create_connection() so that multiple connection errors can be raised as an ExceptionGroup.

some raw datagram functions to the event loop

Added raw datagram socket functions to the event loop: sock_sendto(), sock_recvfrom() and sock_recvfrom_into(). These have implementations in SelectorEventLoop and

contextlib.chdir

用于临时切换工作目录时一个非常方便的上下文管理器, 需要注意的是非并发安全.

Example
import os
from contextlib import chdir

print("当前工作目录:", os.getcwd())

with chdir("/tmp"):
    print("临时切换到目录:", os.getcwd())
    # 在这里执行需要在 /tmp 下完成的操作

print("恢复到原工作目录:", os.getcwd())

New Modules

  1. 内置关于toml的解析库
  2. wsgiref.types 为静态类型检查提供 WSGI 协议方面的支持

Others

  1. [b for a, *b in ([1,2,3], [4,5,6])] 支持在 for 语句中使用*解包
  2. 在异步协程函数中支持异步协程推导表达式, 如 [x asynx for x in async_func()]
  3. 不支持上下文管理器的对象中使用 with 语句将会抛出TypeError而不是AttributeError
  4. 添加object.__getstate__默认实现
  5. 添加 -P命令和PYTHONSAFEPATH环境变量以阻止自动将脚本目录添加到sys.path
  6. sys.path不再接受bytes对象
  7. dataclass 目前接受可哈希的对象作为参数默认值
  8. datetime.UTC -> datetime.timezone.utc
  9. datetime下一些子模块支持解析大多数的ISO8601格式的字符串
  10. enum.EnumMeta 重命名为 enum.EnumType
  11. 新增 enum.StrEnum
  12. gzip.compressmktime=0 时速度更快了
  13. 新增 locale.getencoding()
  14. 新增logging.getLevelNamesMapping() 返回日志级别名称和数值的映射
  15. 新增 math.exp2 返回 2 的 x 次方
  16. math.nan 永久可用
  17. 新增 operator.call 以调用一个对象的可执行方法
  18. re支持原子分组和占有量词特性
  19. 当Unix上C库支持sem_clockwait函数时, threading.Lock.acquire() 将使用time.CLOCK_MONOTONIC代替time.CLOCK_REALTIME
  20. zipfile.Path 新增stemsuffixsuffixes 属性

总结

  1. 说是比 3.10 平均快了 1.25 倍
  2. 异常打印更友好了
  3. 异常捕获时可以通过add_note添加关于上下文的注释, 对于异常信息回溯处理更灵活
  4. 使用asyncio.TaskGroup并发控制一组异步协程任务
  5. 使用asyncio.timeout控制异步协程的超时调度
  6. asyncio.Runner 允许在同一线程内多次调度异步协程代码, 避免重复创建/关闭事件循环带来的性能和安全隐患
  7. dataclass 目前接受可哈希的对象作为参数默认值
  8. enum.verify 装饰器为Enum类增加约束检查
  9. enum.memberenum.nomember允许为 Enum 添加方法作为成员/非成员属性
  10. enum.propertyEnum类添加基于成员的计算属性
  11. Path.glob()Path.rglob() 路径参数以/结尾时, 只返回路径不返回文件
  12. re支持原子分组和占有量词特性
  13. 当Unix上C库支持sem_clockwait函数时, threading.Lock.acquire() 将使用time.CLOCK_MONOTONIC代替time.CLOCK_REALTIME