Python 3.15 上线:等了三年的 lazy import,这次为什么敢写进语言
10 月 9 日Python 3.15.0 正式发布。这个版本由 1,012 位贡献者提交了 5,643 次改动发布经理是 Hugo van Kemenade背后有 Sovereign Tech Agency 的赞助。版本号一出来社区讨论的焦点没放在新语法糖上而是绕回一个老问题Python 启动慢。慢到什么程度一个稍微像样的 CLI 工具比如数据团队内部用的命令行依赖 pandas、SQLAlchemy 和一堆内部 SDK光 import 完依赖再走到真正的业务代码往往要两三秒在 serverless 函数里这两三秒直接算进冷启动账单。原因在 import 机制本身每 import 一个模块解释器都要定位文件、从磁盘读进来、编译成字节码、执行一遍顶层代码。依赖树深的项目哪怕只用到其中一小部分整棵树都得过一遍。Python 社区想动这块已经很久了。上一次是 PEP 690方案走的是隐式路线——默认把所有 import 都改成惰性的语言层面一刀切。讨论了很久2024 年被否掉理由很现实隐式全局改动和现有无数库的假设冲突出了难查的 bug 责任算谁的。这次的 PEP 810 走了另一条路显式、opt-in。新语法长这样lazy import foo。开发者自己决定哪个 import 要惰性惰性只作用于这一句 import不级联到它依赖的其他模块。真正用到 foo 的那一刻才去执行那个模块。改动面小行为可预测兼容性风险也压到了局部。三年前社区吵的那套“全局隐式”方案被一个“你自己挑”的方案替代了。对类型检查器和静态分析工具来说显式写法还有个附带好处工具能直接看出哪些 import 是故意惰性的不会把它误判成未使用的导入。这也是 PEP 810 相比 PEP 690 更容易被生态接受的原因之一——它没要求所有工具一起改行为。机制上值得多讲一句。lazy import foo落地后解释器拿到的是一个延迟绑定的代理对象首次访问foo.某属性、或者把 foo 当参数传进函数、或者对它做dir()这类操作时才真正去执行那个模块的顶层代码。模块一旦加载完后续访问就走正常路径和普通 import 没有差别。这意味着它不会改变现有代码的语义也不会和循环 import 那套老问题冲突——以前因为顶层 import 触发的循环依赖改成惰性之后反而能顺手绕开一部分代价是出错时的堆栈会多一层代理帧调试时认一下就行。除了启动速度3.15 还塞了几个用得上的小东西。PEP 814 把frozendict做成了内置类型——不可变的字典以前大家得自己装第三方包或用 MappingProxyType 凑合PEP 661 加了sentinel内置类型专门替代None当“未设置”的占位符避免 None 本身也是合法值时的歧义PEP 798 允许在推导式里做解包。性能侧还有一笔账。3.13 开始试水的实验性 JIT在 3.15 里做了明显升级官方给的数字是 x86-64 Linux 上几何平均快 7% 到 8%AArch64 macOS 上对比尾调用解释器快 11% 到 12%。JIT 还在实验阶段没默认开方向是把 3.13 那批改动往生产可用推。同版本里 PEP 831 把 frame pointers 默认打开了系统级 perf 这类工具采样 Python 栈能采得更准macOS 官方安装包默认带上 free-threading 支持Windows 64 位官方二进制切到了尾调用解释器。另外几条容易被忽略的改动顺手提一下。PEP 829 引入包启动配置文件允许在包级别声明默认的解释器行为省去在 Dockerfile 或启动脚本里堆一堆环境变量PEP 686 把 UTF-8 设为默认编码绕开 Windows 上历史遗留的 GBK 默认编码坑处理中文和第三方库字符串交互时少踩很多雷。类型系统侧PEP 728 给 TypedDict 加了类型化的额外字段PEP 747 用TypeForm标注类型本身这类改动对写框架和类型检查器的人影响直接业务代码感知不强。生态反应比版本号来得还快。10 月 8 日Pydantic 发 v2.14同一天宣布支持 Python 3.15 的 lazy imports 和 frozendict。这类核心库的跟进速度基本决定了一个新 Python 版本什么时候能被业务项目放心升。这次发布还有个小彩蛋。老贡献者 Barry Warsaw 写了个 TUI 冒险游戏 whatsnewt玩家在解释器里走“启动大厅”到“发布大门”18 个谜题对应的都是 3.15 的真实新特性得真写代码、真跑测试才能解开类型检查环节还会调 pyrefly 验答案。装法一行命令uvx --python 3.15 whatsnewt。回到为什么值得现在翻一翻。3.15 不是那种带 breaking change 的大版本它真正传递的信号是Python 团队在性能和开发者体验两件事上选择了偏保守、可持续的路线。lazy import不替你做决定JIT 不默认开free-threading 先在 macOS 包里默认带上观察。对日常写业务的人来说今年年底到明年上半年大概率会看到一批基础库陆续声明“已支持 3.15”那时候再升级也不迟对维护 CLI 工具、Serverless 函数、打包分发场景的人lazy import这个语法现在就可以在测试分支里试起来了。具体做法不复杂把脚本里启动路径上用不到、却被顺手抄进来的那几个重依赖改成lazy import跑一遍冷启动计时数字往往立竿见影。本文为行业科普分享所涉观点仅代表作者个人理解不构成任何投资、消费、医疗建议。文中提及的产品、地点、数据均来自公开渠道或作者亲身体验或随时间变化。读者据此操作风险自担。