每个 Python 版本都号称更快、更简洁、更智能、更符合人体工程学……
但大多数时候,这些变化要么极其小众,要么只是技术上很厉害,和人们编写 Python 的方式没什么关系。
Python 3.15 给人的感觉不一样。
并不是因为每个新特性都具有革命性。有些功能说实话早就该有了;有些功能更像是在为之前的实验性设计做收尾清理;还有一些,则是编程语言爱好者才会在意的东西。
近年来Python发布的版本不少,真正对开发者影响明显的少之又少,Python 3.15是其中之一。
仅仅延迟导入(lazy imports)这一项,就会改变很多大型 Python 应用的启动方式。
有意思的是,Python 3.15 还回滚了 Python 3.14 中一个最大的改动。
老实说,这是 Python 开发文化的真实体现。他们推出了增量垃圾回收器(incremental garbage collector),结果大家抱怨内存占用有问题,于是又把它移除了。
这种文化挺好,比假装每一个实验性改动都“英明伟大”要健康得多。
1 延迟导入(lazy imports)这东西本来几年前就该有了
这大概是这次发布最实用的功能。
Python 启动速度一直有个奇怪的问题:它会导入半个生态系统,这像是在代码真正运行前交了一遍税。
你导入一个框架,那个框架再导入六个工具模块,那些模块又继续导入二十多个。最后,你的 CLI 工具光是输出一个 --help 就要花两秒钟。
很多年来,人们一直在手动绕开这个问题:
if expensive_feature_enabled: import pandas
或者:
def do_something(): import torch
不是因为这样写更优雅,而是因为启动延迟真的很重要。
现在,Python 终于官方支持延迟导入了。
模块可以等到真正被使用时再加载,而不是在启动阶段一股脑全部导入。更重要的是,很多现有的 import 语句都能直接变成延迟加载,不需要把整个代码库重构成被依赖关系诅咒的迷宫。
这一点,比语法本身更重要。
它真正的价值体现在:
CLI 工具
开发者工具链
大型 Web 应用
那些 import 树离谱到爆炸的 AI 技术栈
基本上所有一不小心就长成“操作系统”的 Python 项目
而且,如果你的代码本来就写得很规范,这个特性几乎没什么副作用。
不过说实话:有些项目大概要第一次意识到,自己对 import 副作用的依赖比想象中严重得多。比如假定import时会执行某个逻辑,但因为现在变成lazy import了,这个逻辑不会马上执行。如果项目有这样对import副作用的依赖,要改过来。
Python 开发者总是喜欢假装 import 只是声明,但很多 import 本质上是穿着import马甲的初始化脚本。
2 JIT 终于在基准测试里“看得见”了
Python 在 3.13 版本中引入了 JIT。
当时大家的反应基本是:“哦,行吧。挺酷的。然后呢?”
因为性能提升既小又不稳定。
这倒不一定算失败,最初几个版本更像是在铺基础设施。问题在于,人们一听到JIT 编译器,期待的往往是那种非常夸张的性能飞跃。
Python 3.15 是第一个让这些改进开始显得“真实”的版本。
根据不同工作负载和平台,官方报告的性能提升大约在 8% 到 13% 的几何平均值之间。
当然,这并不会突然把 Python 变成 Rust。
但对于这样一种被广泛使用的语言来说,自动获得 10% 左右的性能提升,也绝对不算小事。
尤其是因为,大多数 Python 性能优化工作通常意味着:
用 C 重写热点路径
把所有东西都硬塞进 NumPy 向量化
到处加缓存层
假装 asyncio 解决了架构问题
如果 CPython 能继续在不要求整个生态系统重写的前提下,让“普通 Python”变得更快,这件事就很重要。
更有意思的是,这些 JIT 提升并不是靠某个“大招”实现的,而是一整套运行时优化的组合:
tracing(追踪)机制改进
更好的机器码生成
寄存器分配优化
引用计数优化
基本上全是那种绝大多数 Python 用户不会想到的底层工程细节——除非他们哪天手滑打开了 CPython 内部源码。
开发者会立刻感觉到差异吗?这取决于具体工作负载。
和之前几个版本不同的是,这次终于不只是“理论上的提升”了。
3 frozendict 属于那种争论了很多年的功能
Python 几乎不会新增内置数据结构。
一旦真加了,意味着整个生态已经用各种糟糕的方式把同一个东西重复造了一千遍。
frozendict 就是这种情况。
不可变字典以前早就在各种库里存在了。有人用 tuple 变通实现;有人包装普通 dict;还有人专门写自定义类。
现在终于有了官方版本。
config = frozendict({"host": "localhost", "port": 5432})
你没法修改它。它是可哈希的(hashable),可以安全地作为字典的键来使用。
很简单。
说实话,这不像是什么炫酷的新特性,更像是 Python 终于承认了现实。
4 sentinel() 修复了一个出奇烦人的老问题
这是那种乍一听不重要,但只要你 Python 写得够久,就一定会遇到的功能。
很多代码库里都会这么写:
MISSING = object()
为什么?因为 None 有时候本身就是合法值。
所以开发者只能创建一个匿名、唯一的对象充当占位符。
问题在于,这种对象既丑陋,又缺乏自解释性,对类型检查也不友好,而且整体上总给人一种“临时凑合”的感觉。
现在终于有了官方 API:
NOT_SET = sentinel("NOT_SET")
可读性更好了,打印输出更正常,和类型系统的配合也更自然。
这恰恰是 Python 最擅长的那类语言改进。
不是什么革命性突破,只是把一些没必要的“奇怪写法”慢慢消灭掉而已。
5 新的性能分析器(profiler)比很多人意识到的还要重要
Python 的性能分析工具一直有个经典权衡:
要么获得非常精确的分析结果,但需要付出巨大的运行开销
要么获得轻量级监控,但细节会少很多
cProfile 会追踪所有东西,而这也意味着会显著拖慢程序运行。
Python 3.15 增加了一个“统计采样式(statistical sampling)”分析器。
这其实更适合偏生产环境的性能分析。
它不再追踪每一次函数调用,而是周期性地对程序执行状态进行采样,然后估算时间到底花在了哪里。
精度没那么绝对,但代价低得多,而且通常已经“够用了”。
说实话,很多现代性能分析工具本来就是这么工作的,只是 Python 在这方面显得有点落后。
当然,这并不意味着确定性分析器(deterministic profiler)会消失。在某些调试场景,它们依然非常重要。
但对大多数常规优化工作来说,采样式 profiler 才是更现实的选择。
尤其是开发者本来就不愿意做 profiling——因为 profiling 本身会改变程序运行行为。
6 错误信息终于变得没那么糟糕了
过去发布的几个版本,Python 错误提示已经进步了很多。
这听起来像小事,直到你回头看看老版本 Python 的报错——那时候的错误信息就像是在对你耸肩:“Ops,出错了,自己想办法吧。”
Python 3.15 进一步改进了错误建议功能。
有个挺搞笑的例子:
my_list.push(1)
现在 Python 会意识到,你大概率是“JavaScript 脑子还没切换过来”,然后建议使用:
append()
这其实非常有用。
说到底,现代开发本来就经常在不同语言之间来回切换,所以这种错误完全正常。
而且,属性名建议(attribute suggestions)整体也变得更聪明了。
这不是什么颠覆性改进,但开发体验这种东西,本来就是一点一点累积起来的。
很多人低估了那些“愚蠢的调试摩擦”到底会浪费多少精力。
7 推导式(comprehension)解包功能,看起来是个小改动,其实对可读性影响很大
这个特性大概会把人分成两派:
“终于来了。”
以及:
“这会让推导式彻底变成天书。”
说实话,这两种反应都挺合理。
以前,在推导式里展开嵌套可迭代对象,通常得这么写:
[a for b in x for a in b]
技术上当然没问题,但也谈不上好读。
现在可以写成:
[*a for a in x]
扫一眼就更容易理解。
字典解包现在也支持:
{**d for d in dicts}
这个功能本身很直白。
真正的问题在于,Python 推导式本来就很容易在“过度聪明”之后,逐渐演变成某种编程竞赛谜题。
所以这大概属于那种:适度使用时非常棒,但落到那些把“单行代码”当成人格特质的开发者手里,就会变得非常可怕。
8 垃圾回收器(GC)的回滚,其实是个好信号
从“理念”层面说,这可能是这次发布最有意思的一部分。
Python 3.14 曾引入一种“增量式垃圾回收器(incremental garbage collector)”,目标是减少程序停顿时间(pause times)。
这个目标本身很合理。
但随后,用户开始报告内存占用增加的问题,有时候甚至增加得相当夸张。
于是 Python 3.15 把这个改动回滚了。
说实话,这完全没问题。
一个会导致内存膨胀的运行时优化,并不会因为实现起来很复杂,就值得保留下来。
有些技术生态有种倾向:只要是“性能实验”,无论效果如何,都要拼命维护到底,因为回滚看起来像是在承认失败。
Python 选择撤回这个改动,而不是假装用户“想多了”,其实是更健康的做法。
所以旧的“分代垃圾回收器(generational garbage collector)”又回来了。
至于增量 GC,以后可能还会在进一步完善后重新出现。
这才是正确的结果。
9 类型系统持续扩展,让 Python 的“分裂人格”越来越明显
Python 的类型标注(typing)一直在演变成一个平行宇宙。
有些开发者很喜欢它,有些只是勉强接受,还有一些人仍然把类型注解当作“装饰性的注释”。
Python 3.15 在 TypedDict 上增加了更多控制选项,比如:
closed
extra_items
这些让字典结构的约束更严格,也更具表达力。
此外还有 TypeForm,用于更好地表示“已求值的类型表达式”。
有用吗?有。
让人兴奋吗?这取决于你有多少时间在和静态分析工具搏斗。
现实情况是,Python 现在同时服务于两种非常不同的用户群:
一类是想要灵活脚本能力的人
另一类是构建大规模类型化系统的开发者
有时候语言能很好地处理这种张力,有时候则更像是两种语言共享同一套语法。
10 Python 3.15 给人的感觉是不同寻常地务实
这大概是最核心的一点。
很多版本都包含大量令人印象深刻的底层工程,但普通开发者几乎感知不到。
而 Python 3.15 包含的几项改动,确实直接影响到:
启动性能
性能分析(profiling)
运行时速度
错误调试体验
数据建模
代码可读性
并不是每个功能都同样重要。有些很小众,有些甚至会在 Reddit 上引发持续半年的争论。
但整体来看,这个版本更像是基于真实开发行为、而不是语言理论来设计的:
人们抱怨启动速度慢,Python 就加入了延迟导入(lazy imports)
人们想要不可变字典,Python 就提供了 frozendict
用户反馈 GC 有内存问题,Python 就回滚了相关改动
这种反馈闭环可能是最让人安心的部分。
我仍然认为,一些 Python 应用正在变得过度工程化。尤其是 AI 生态,经常在打印一个 token 之前,就先把全地球的包导入一遍。
至少 CPython 本身,似乎越来越专注于解决实际痛点,而不是假装“开发体验”和“运行时行为”是两件互不相关的事情。
这些改动在 3.15 完全发布后、进入真实项目会变成什么样,还有待观察。
有些特性会悄悄变成常态,有些会被迅速滥用。
有些可能在未来版本中移除。
这也很 Python。
扫码二维码 获取免费视频学习资料

- 本文固定链接: http://phpxs.com/post/14192/
- 转载请注明:转载必须在正文中标注并保留原文链接
- 扫码: 扫上方二维码获取免费视频资料