工具推荐·阅读约 2 分钟·
Python 3.15 低调发布:那些被头条忽略的宝藏特性

Python 3.15 低调发布:那些被头条忽略的宝藏特性

Python 3.15 beta 1 已经冻结功能。除了懒加载和 Tachyon 分析器等大特性,TaskGroup 优雅取消、上下文管理器装饰器改进、线程安全迭代器和 Counter XOR 等小特性同样值得关注。

原文来源:Jamie Chang's Blog — Python 3.15: features that didn't make the headlines — 2026 年 5 月 13 日发布。Python 3.15 官方文档参考 docs.python.org/3.15/whatsnew/3.15.html

每到这个时候,Python 的新版本又开始向我们走来。随着 Python 3.15.0b1 功能冻结,我们已经知道了今年晚些时候会带来什么。大家的目光都在懒加载(Lazy Imports)和 Tachyon 采样分析器这些大功能上,但这些小功能同样值得关注。

Asyncio TaskGroup 优雅取消

TaskGroup 是结构化并发的一种形式,让开发者以干净的方式创建多个并发任务。以前如果要在后台等待一个信号来中断 TaskGroup 的执行,过程相当别扭:

code
class Interrupt(Exception):
    ...
 
with suppress(Interrupt):
    async with asyncio.TaskGroup() as tg:
        tg.create_task(run())
        tg.create_task(run())
        if await wait_for_signal():
            raise Interrupt()

上面的代码能工作,因为 TaskGroup 中的异常会导致其他任务被取消。自定义的 Interrupt 异常作为 ExceptionGroup 的一部分抛出,然后被 contextlib.suppress 过滤掉。

在 Python 3.15 中,TaskGroup.cancel() 让这一切变得非常简单:

code
async with asyncio.TaskGroup() as tg:
    tg.create_task(run())
    tg.create_task(run())
    if await wait_for_signal():
        tg.cancel()

简单到不需要解释——它直接取消整个组,不抛出任何异常。

上下文管理器改进:终于能当装饰器用了

你知道吗?上下文管理器从 Python 3.3 开始就可以兼作装饰器:

code
@contextmanager
def duration(message: str) -> Iterator[None]:
    start = time.perf_counter()
    try:
        yield
    finally:
        print(f"{message} elapsed {time.perf_counter() - start:.2f} seconds")
 
@duration('workload')
def workload():
    ...

但之前有一个问题:对于异步函数和生成器,它不工作

当你对 async defdef 生成器函数使用这个装饰器时,调用它们会立即返回(协程对象或生成器对象),而不是覆盖整个生命周期。这在 3.15 中被修复了——ContextDecorator 现在会检查被包装函数的类型,确保装饰器覆盖整个生命周期。

个人来看,这使上下文管理器成为创建装饰器的最佳方式。它避免了一些常见的陷阱,语法也更简洁。

线程安全迭代器

迭代器是 Python 的基础设施之一。但默认情况下,迭代器不是线程安全的。在多线程或自由线程(free-threading)环境中使用同一迭代器,可能会出现跳过值或内部状态损坏的问题。

Python 3.15 用 threading.serialize_iterator 解决了这个问题:

code
import threading
 
events = threading.serialize_iterator(stream_events(...))
 
with ThreadPoolExecutor() as executor:
    fut1 = executor.submit(consume, events)
    fut2 = executor.submit(consume, events)

还有 threading.synchronized_iterator 装饰器,直接应用到生成器函数上:

code
@synchronized_iterator
def stream_events():
    ...

以及 threading.concurrent_tee,它不是分割值,而是将值复制到多个迭代器中:

code
source1, source2 = threading.concurrent_tee(squares(10), n=2)
 
with ThreadPoolExecutor() as executor:
    fut1 = executor.submit(consume, source1)
    fut2 = executor.submit(consume, source2)

以前我们需要依赖 Queue 来协调线程间的消费,有了这些工具,多线程代码的抽象层不再需要改变了。

惊喜一:Counter 的 XOR 操作

collections.Counter 是一个非常实用的类,它像 dict[KeyType, int] 一样工作,但有一堆方便的操作:

code
c = Counter(a=3, b=1)
d = Counter(a=1, b=2)
 
print(f"{c + d = }")  # Counter(a=4, b=3) — 相加
print(f"{c - d = }")  # Counter(a=1, b=0) — 相减(只保留正数)
print(f"{c & d = }")  # Counter(a=1, b=1) — 交集:min(c[x], d[x])
print(f"{c | d = }")  # Counter(a=3, b=2) — 并集:max(c[x], d[x])

在 Python 3.15 中,加入了 XOR 操作:

code
c ^ d == Counter(a=2, b=1)
# 等于 (c | d) - (c & d)

可以把它理解为集合的对称差集:出现在任一 Counter 中但不同时出现的元素。虽然实际用途可能有限,但 API 完整性是好事。

惊喜二:不可变 JSON 对象

Python 3.15 引入了 frozendict,配合 JSON 模块的新 array_hook 参数,现在可以方便地将 JSON 解析为完全不可变(可哈希)的形式:

code
json.loads('{"a": [1, 2, 3, 4]}',
           array_hook=tuple,
           object_hook=frozendict)
# 返回 frozendict({'a': (1, 2, 3, 4)})

array_hook 是对 object_hook 的补充,以前 JSON 模块支持自定义对象钩子,但不支持自定义数组类型。现在两者都有了,JSON 解析的可定制性上了一个台阶。

总结

Python 3.15 并不是一个"革命性"的版本——懒加载和 Tachyon 分析器才是真正的亮点。但如果你已经熟悉那些大功能,这些"小功能"恰好是日常编码中最实用的部分。

  • TaskGroup.cancel() —— 异步编程更顺手了
  • ContextDecorator 的异步兼容 —— 装饰器写法更统一了
  • threading.serialize_iterator —— 多线程迭代不再头疼
  • Counter XOR + array_hook —— API 完整性和细节打磨

这些变化虽小,但每一个都是 Python 开发者在实际工作中踩过的坑。Python 3.15 beta 已经可以试用了,正式版预计下半年发布。

延伸阅读

分享到
微博Twitter

© 2026 四月 · CC BY-NC-SA 4.0

原文链接:https://aprilzz.com/tools/python-315-hidden-features