Python 3.15 正式发布:三个让脚本更顺手的新特性

Python 3.15 正式发布:三个让脚本更顺手的新特性

这是什么版本

Python 3.15.0 在 2026 年 10 月 9 日正式发布,是 Python 一年一度的大版本更新。按惯例本该 10 月初推送,因为修复 lazy import(懒加载导入)引入的一个回归 bug,多推迟了一周。

官方发布说明里提到:这个版本包含 5,643 次提交、1,012 位贡献者的工作。最受关注的变化有四个:显式懒加载导入(PEP 810)、内置 frozendict(PEP 814)、全平台默认 UTF-8 编码(PEP 686),以及一个能"盯着正在运行的程序看"的采样分析器 Tachyon(PEP 799)。

如果你在 VPS 上跑定时脚本、在 Windows 和 Linux 之间搬代码,或者写命令行小工具,这次有三个特性值得花十分钟了解一下。

1. lazy import:启动慢的脚本有救了

很多命令行工具启动慢,不是因为逻辑重,而是 import 链太长:pandas、requests、yaml 全在文件头 import 进来,哪怕这次运行只用到其中一个。以前没有官方的懒加载机制,大家只能靠函数内 import 或者 importlib 手搓。

3.15 加了一个 lazy 关键字:

lazy import pandas as pd

def export_report(rows):
    return pd.DataFrame(rows).to_csv(index=False)

import sys
print("pandas" in sys.modules)  # False:还没真正加载
export_report([{"city": "北京", "temp": 18}])

lazy import pandas 只绑定名字,真正的导入发生在第一次使用 pd 的那一刻。PEP 810 的作者称,真实工作负载下启动时间最多能缩短 50%~70%,内存占用也更低。

几个实用细节:

  • 老代码不受影响:只有显式写了 lazy 才懒加载,普通 import 行为完全不变。
  • 全局开关:不想逐行改,用 python -X lazy_imports=all 脚本.py,或设置环境变量 PYTHON_LAZY_IMPORTS=all。
  • 兼容旧版本:写 __lazy_modules__ = ["json", "pathlib"],在 3.15 上这些导入变懒,在 3.14 及更早版本这行会被直接忽略,适合要同时支持多个版本的可分发脚本。
  • 限制:lazy 只能写在模块顶层,函数里、类里、try 块里用会报 SyntaxError。

对定时任务里跑的巡检脚本、CLI 工具来说,冷启动快一秒感知都很明显。

2. UTF-8 成默认编码:跨平台脚本的老大难解决了

以前 Python 读文本文件不传 encoding 参数时,Linux/macOS 默认 UTF-8,Windows 却跟着系统区域设置走(中文 Windows 是 GBK)。同一份脚本在 Linux 跑得好好的,搬到 Windows 就报 UnicodeDecodeError,或者更糟——静默乱码。

PEP 686 让 UTF-8 成为所有平台的默认编码:open("data.txt") 现在到处都是 UTF-8。

注意两点:

  • 如果你的老脚本恰好"依赖"了 Windows 下默认 GBK 的行为(读 GBK 文件但没写 encoding),升级后会反过来报错。兜底是环境变量 PYTHONUTF8=0 恢复旧行为,或者——更推荐——把该加 encoding= 的地方补上。
  • 新写的脚本依然建议显式传 encoding="utf-8":显式永远比隐式可靠,代码搬到哪都不会踩坑。

3. frozendict 和 sentinel:两个小而美的内置类型

frozendict(PEP 814):创建后不可修改的字典,天然适合当配置常量或缓存 key。

DEFAULTS = frozendict(host="example.com", port=443, timeout=30)
DEFAULTS["port"] = 80   # TypeError:改不动

它不是 dict 的子类,isinstance(x, dict) 会判它为 False;要同时接受两种,写 isinstance(x, (dict, frozendict)) 或用 collections.abc.Mapping。键值都可哈希时它本身也可哈希,能直接当字典的 key。

sentinel(PEP 661):"没有传值"终于有了官方标准写法。以前大家用 _MISSING = object() 手搓哨兵值,现在:

def connect(host, port=sentinel("port")):
    if port is sentinel("port"):   # 区分"没传"和"传了 None"
        port = 443

顺带一个语法糖:推导式里可以用解包了(PEP 798):

flat = [*x for x in [[1, 2], [3, 4], [5]]]      # [1, 2, 3, 4, 5]
merged = {**d for d in [{"a": 1}, {"b": 2}]}    # {'a': 1, 'b': 2}

以前要写双层 for 的展平操作,现在一行搞定。

4. 性能和其他

实验性 JIT 编译器继续提速:官方基准显示,x86-64 Linux 上比标准解释器快 7~8%,AArch64 macOS 上比 tail-calling 解释器快 11~12%。注意这是"特定基准测试的几何平均",不是所有程序都快这么多,JIT 本身也依然是实验性的。

Tachyon 是新的高频统计采样分析器,能 attach 到正在运行的进程上,不用重启、不用改代码,适合给线上服务做"哪里慢"的快速定位。相关工具被收拢进了一个专门的 profiling 包(PEP 799)。

要不要现在升级?

先看兼容:3.15 和 3.14 语言层面保持向后兼容,但 C 扩展需要重新编译——numpy、pandas 这类重度依赖 C 扩展的库,通常要等上游发布适配 3.15 的 wheel。生产环境装了大量二进制包的话,建议等 3.15.1 或等常用库都发适配版再动。

版本寿命参考:Python 3.14 的官方支持到 2030 年 10 月,3.15 到 2031 年 10 月,老项目完全可以按自己的节奏来。

  • 新项目/新脚本:直接用 3.15,lazy import 和 UTF-8 默认能省不少麻烦。
  • 已有稳定服务:先在测试环境装一个,跑通依赖再升级生产。
  • 只想尝鲜:用 pyenv 或官方安装包单独装一个 3.15,不动系统默认版本。

安装包在 Python 官网的 3.15.0 发布页,完整的新特性列表看官方发布公告,想系统学一遍可以看 Real Python 的 3.15 课程。写 Python 安全脚本的话,也可以回看昨天的 PyPI 恶意包安检脚本。