跳到正文
Simon Willison·· 5 天前AI 评分22

Python 3.15 发布:告别 3.10,拥抱 3.11 新特性

Hello Python 3.15, goodbye 3.10, and now I can use 3.11

AI 导读

Python 3.15 正式发布,带来 PEP 810 显式惰性导入、推导式解包语法和标准库采样分析器 Tachyon(profiling.sampling)。

正文 · AI 翻译

2026年10月12日

Python 3.15 来了!这里是必备的 Python 3.15 新特性指南,今年由 3.14 和 3.15 的发布经理 Hugo van Kemenade 策划。作为一个构建能在所有受支持 Python 版本上运行的开源软件的人,我可以告别 Python 3.10,开始拥抱 Python 3.11 的特性了。

首先,是 Python 3.15 的一些亮点。

显式惰性导入

我最兴奋的是来自 PEP 810 的显式惰性导入。它们让你可以像这样导入模块:

lazy import json
lazy from pathlib import Path

然后,当后续代码中首次使用这些符号时,模块才会被导入。

我的 LLM CLI 工具实现了插件。我不得不在插件作者文档中建议手动进行惰性导入,因为仅仅安装使用了诸如 sentence_transformers 这类重量级依赖的插件,就可能让每次调用 llm 命令增加数秒时间。惰性导入直接解决了这一启动开销。

推导式中的解包

新的 [*sublist for sublist in lists] 解包语法很简洁。这里有一个摘自文档的示例:

lists = [[1, 2], [3, 4], [5]]
[*L for L in lists]
# [1, 2, 3, 4, 5]
# equivalent to [x for L in lists for x in L]

sets = [{1, 2}, {2, 3}, {3, 4}]
{*s for s in sets}
# {1, 2, 3, 4}
# equivalent to {x for s in sets for x in s}

dicts = [{'a': 1}, {'b': 2}, {'a': 3}]
{**d for d in dicts}
# {'a': 3, 'b': 2}
# equivalent to {k: v for d in dicts for k,v in d.items()}

PEP 798:推导式中的解包由 Adam Hartz 和 Erik Demaine 提出,作为来自 PEP 448 的解包语法的扩展,该语法于 2015 年在 Python 3.5 中落地。

采样分析器

Python 现有的跟踪分析器已从 cProfile 重命名为 profiling.tracing,并迎来了一个令人兴奋的新采样分析器,名为 Tachyon,又名 profiling.sampling。

采样分析器的工作原理是定期从运行中的进程捕获堆栈跟踪,然后利用这些信息计算出哪些函数在其中花费的时间最多。它们的开销非常低,无需事先对系统进行插桩,就能提供对运行中系统的深入洞察。

我以前使用过像 py-spy 这样的工具来做这件事。现在这一能力已内置到标准库中。

如果你有一个现有 Python 3.15 进程的 PID,可以通过运行以下命令开始收集样本(在 macOS 上我不得不使用 sudo):

sudo uv run --python 3.15 python -m profiling.sampling attach 1234

与主程序交互一下,然后按 Ctrl+C 停止收集并查看报告,报告看起来像这样:

Screenshot of terminal output from a Python sampling profiler with colored text on a black background. Header lines report 2,651 samples captured in 2.65 seconds at a sample rate of 999.98 samples/sec with an error rate of 0.19. A Profile Stats table with columns for nsamples, sample%, tottime, cumul%, cumtime and filename:lineno(function) shows that 99.9% of samples (2.644 seconds) were spent directly in selectors.py KqueueSelector.select, meaning the process was almost entirely idle waiting on the asyncio event loop. The rest of the table lists the call stack beneath it with zero direct time but 100% cumulative presence: asyncio base_events.py run_once, run_forever and run_until_complete, runners.py Runner.run and run, cli.py serve and sqlite_extensions wrapped, and several click core.py invoke, main and call frames. A legend explains each column, followed by a Summary of Interesting Functions section listing hot spots (KqueueSelector.select at 99.9% direct samples), the most frequently present functions on the stack (run_forever, run_until_complete and Runner.run at 100%), and the highest call magnification (2645.0x for BaseEventLoop._run_once).

它还可以生成像这样的火焰图和像这样的热力图,甚至能输出可在 Firefox 分析器 UI 中查看的格式。

3.15 并不比 3.14 快多少

Miguel Grinberg 前几天针对 3.15.0rc3 版本调查了Python 3.15 有多快?,发现性能与 3.14 基本持平,实验性 JIT 除外。JIT 相比标准的 3.15 解释器带来了 1.2 倍的提升(在斐波那契测试中),这是 Miguel 首次观察到 JIT 性能有意义的提升。

Miguel 去年对 3.14 的探索发现,在更多类别上相比 Python 3.13 都有显著提升。

使用 uv 升级到 Python 3.15

我使用以下命令序列让 uv 在我的 Mac 上使用 Python 3.15。首先我必须升级 uv 本身,以确保它知道这个新版本:

uv self update

然后我安装了稳定的 3.15 版本:

uv python install 3.15

并告诉 uv 我希望它成为每个 uv run 命令的默认版本,除非项目本身固定了不同的版本:

uv python pin --global 3.15

现在以下命令报告版本为 3.15:

uv run python --version

我已经用 uv tool install 安装了一堆工具。我像这样重新安装它们以使用 Python 3.15:

uv tool upgrade datasette --python 3.15

然后我可以像这样确认版本:

datasette --get /-/versions.json | jq

Python 3.11 亮点

3.15 的发布意味着 Python 3.10(2021 年发布)已正式不再受支持。

我对主要开源项目的策略是让它们在所有受支持的 Python 版本中都能正常工作。现在我可以放弃 3.10,并开始使用 3.11 中引入的功能。

这里是Python 3.11 新特性文档。我终于可以依赖 tomllib 了!

Datasette 大量使用了 asyncio。3.11 新增了 TaskGroup 和 timeout(),以及其他几项新功能。

datetime.UTC 是 3.11 中新增的 datetime.timezone.utc 的别名。

Python 的 SQLite 支持在 3.11 中获得了重大升级,包括:

  • setlimit() 和 getlimit() 提供了一种从 Python 设置 SQLite 运行时限制的机制。
  • create_window_function() 让我们可以在 Python 中创建自定义窗口函数,作为一个具有 step()、value()、inverse() 和 finalize() 方法的类。
  • blobopen() 提供了一种高效机制,用于对存储在 SQLite 行中的大型 BLOB 二进制值进行部分读写。
  • 现在你可以调用 set_authorizer(None) 来移除 SQLite 授权器。Datasette 之前为此有一个变通方案!

此外还有一大堆对 Python 类型系统的改进。

我计划在未来几周内将 Python 3.11 的改进应用到我的多个项目中。这是我第一个 Datasette PR,移除了那个 set_authorizer(None) 变通方案。

我还更新了我的 click-app、datasette-plugin、python-lib 和 llm-plugin cookiecutter 模板,以针对 Python 3.11 到 Python 3.15 进行测试。

来源:Simon Willison · simonwillison.net