社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

Python 3.15 来了:不改一行代码,你的 Python 已经更快了

IT服务圈儿 • 2 月前 • 162 次点击  
来源丨经授权转自 数据STUDIO
者丨云朵君

Python 3.15.0b1 在上个月发布了。我没急着写——beta 版本嘛,谁知道后面还会不会改。但现在 beta 2 出来,feature freeze 已经锁死,该聊了。

先给你看个东西:

# 以前:import 就加载,哪怕这个函数根本不会走到
import heavy_json_processor  # 启动 +300ms

def handle_request(data):
    if data["type"] == "simple":
        return data  # json 模块白加载了
    return heavy_json_processor.process(data)


# Python 3.15:用的时候才加载
lazy import heavy_json_processor

def handle_request(data):
    if data["type"] == "simple":
        return data  # 根本没加载,省了 300ms
    return heavy_json_processor.process(data)

就这一行 lazy,你的 CLI 工具启动可能快一半。先记着这个,后面展开。

TL;DR

  • Python 3.15 不是功能大爆炸版本——它是把散布在第三方的最佳实践(懒加载、不可变映射、采样 profiler)吸收为语言基础设施的"工程化补齐"版本
  • 6 个跟数据工程师直接相关的变化:lazy import / frozendict / 推导式解包 / JIT 升级 / Tachyon profiler / GC 回退
  • 不改一行代码,ARM Mac 上的 Python 跑快 12-13%。改了的话——lazy import 能让 CLI 启动减半
  • 升级姿势:用 pyenv install 3.15.0b2 本地测;生产等到 10 月正式版

01版本疲劳?这次不一样

我知道你在想什么。

Python 3.13 说 JIT 来了,3.14 说 GC 重写了,3.15——又一个版本号。大部分 Python 开发者还在 3.11 上跑着,懒得动。

但 3.15 有个微妙的区别:它不要求你学新概念。

lazy import 就是在 import 前面加一个词。frozendict 就是你一直在用 tuple(sorted(d.items())) 做的那个事,现在原生支持了。JIT 升级是你睡一觉起来它就快了的改动。

而且 3.14 那个出问题的增量 GC——在 3.15 修好了。直接回退到 3.13 的分代回收,稳了。所以如果你跳过了 3.14,3.15 是更好的起跳点。

真正让我觉得这版本值得写一篇文章的,不是某个单一特性,而是看完 14 个 PEP 之后的一个判断——Python 正在完成它的"工程化成人礼"。

一个一个说。


02三层结构:你看得见的、看不见的、和地基

如果把 Python 3.15 的改动摊开来看,它们自然分成三层:

┌─────────────────────────────┐
│  Syntax Surface(语法层)     │  ← 你每天敲的代码
│  lazy import / frozendict    │
│  unpack comprehension        │
├─────────────────────────────┤
│  Performance Engine(性能层) │  ← 你看不见但感受得到
│  JIT 升级 / Tachyon profiler │
│  frame pointers              │
├─────────────────────────────┤
│  Ecosystem Foundation(地基) │  ← 平时不关心,塌了是灾难
│  UTF-8 默认 / GC 回退        │
│  .start 文件 / abi3t         │
└─────────────────────────────┘

这个分层不是官方分类——是我看完 14 个 PEP 之后自己理出来的。每一层解决一个层级的问题,合在一起回答一个问题:一个 34 岁的语言,怎么在不破坏生态的前提下继续变快、变安全、变更可观测?

语法层解决"写得爽不爽"。性能层解决"跑得快不快"。地基解决"部署时会不会炸"。

下面按层拆开。每层挑跟你最相关的说。


03语法层:三个新工具,替换你的 workaround

lazy import:让 import 变懒

Python 的 import 是 eager 的——import 语句执行时立刻加载整个模块。这在 CLI 工具和多服务应用中特别伤:你可能 import 了 20 个模块,但实际处理一个请求只需要其中 2 个。

3.15 的解法是一个新的软关键字 lazy

lazy import json
lazy from pathlib import Path
lazy import numpy as np
lazy from .utils import heavy_parser

# 以上四行不加载任何模块。加载发生在第一次使用时
data = json.loads('{"a": 1}')  # json 在这一行才加载

如果加载失败(比如模块不存在),报错也推迟到使用点,traceback 里会同时显示调用位置和原始 import 语句。

全局控制有三种方式:

# 全部懒加载(激进——可能破坏依赖 import 副作用的代码)
export PYTHON_LAZY_IMPORTS=all

# 命令行启动
python -X lazy_imports=all your_script.py

更安全的做法是用 filter 函数,只懒加载你自己的模块:

import sys

def my_filter(importing, imported, fromlist):
    return imported.startswith("myapp.")

sys.set_lazy_imports_filter(my_filter)
sys.set_lazy_imports("all")

import myapp.slow_module  # 懒加载
import json                # 立即加载(不受影响)

兼容旧版本 Python 的项目可以用 __lazy_modules__ 列表做向后兼容——3.15 以下版本直接忽略这个变量,行为不变。

跟你有什么关系:如果你写 CLI 工具、API 服务、或者 import 了 torch/tensorflow 这种重型库但只用其中少数函数——lazy import 是 3.15 最直接可用的性能提升。

frozendict:终于不用 tuple(sorted(d.items())) 了

Python 的 dict 一直有个尴尬:你需要一个不可变的、可哈希的映射来做缓存 key 或配置常量,但 dict 本身可变且不可哈希。

以前的 workaround:




    
# 又丑又慢
CACHE_KEY = tuple(sorted(config.items()))

# 或者用 MappingProxyType,但它不是 dict-like
from types import MappingProxyType
CONFIG = MappingProxyType({"host""localhost""port"5432})

3.15 直接给了 frozendict——一个新的 builtins 类型:

>>> config = frozendict(host="localhost", port=5432)
>>> config["host"]
'localhost'
>>> config["port"] = 3306
TypeError: 'frozendict' object does not support item assignment

# 可哈希,直接做 dict key 或 set 元素
>>> cache = {}
>>> cache[frozendict(a=1, b=2)] = "result"

# 比较跟插入顺序无关
>>> a = frozendict(x=1, y=2)
>>> b = frozendict(y=2, x=1)
>>> a == b          # True
>>> hash(a) == hash(b)  # True

jsonpicklepprintcopymarshal 这些标准库模块已经适配了 frozendict。

一个需要注意的迁移点:如果你代码里用了 isinstance(x, dict) 做类型检查,frozendict 不会被匹配到(它不继承 dict)。改成 isinstance(x, collections.abc.Mapping) 就能同时覆盖 dict 和 frozendict。

推导式里终于能 unpack 了

这个说起来简单,但确实好用:

# 以前:嵌套推导,可读性一塌糊涂
>>> lists = [[12], [34], [5]]
>>> [x for L in lists for x in L]
[12345]

# 3.15:直接 unpack
>>> [*L for L in lists]
[12345]

# dict 也支持 **
>>> dicts = [{"a"1}, {"b"2}, {"a"3}]
>>> {**d for d in dicts}
{'a'3'b'2}

小语法糖,但写数据处理 pipeline 的时候少嵌套一层就是一层。


04性能层:不改代码,它就变快了

JIT:ARM Mac 上快 12-13%

Python 3.13 引入了 JIT 编译器,3.14 继续优化,3.15 上了"显著升级"(官方原话)。具体数字:

  • x86-64 Linux:几何平均提升 8-9%
  • Apple Silicon (ARM64) macOS:几何平均提升 12-13%
  • Windows 64-bit:官方二进制现在默认启用 tail-calling interpreter

这些提升不需要你改任何代码。升级 Python 版本就有了。而且 12-13% 在 ARM Mac 上不是小数点后两位——是完全可以感知的差距。如果你的数据处理脚本原来跑 10 秒,现在 8.7 秒。

Tachyon:Python 终于有个像样的 profiler 了

这是 3.15 我最期待的特性。

以前的 Python profiling 是两难:cProfile 是 deterministic tracing,本身有大量开销,测出来的结果跟真实性能偏差不小。timeit 只能测微基准。py-spy 是第三方工具,需要单独安装,功能有限。

3.15 的 Tachyon 是内置的 统计采样 profiler——原理类似 Linux perf,高频采样调用栈,几乎零开销:

# 直接运行并采样
python -m profiling.sampling your_script.py

# 附加到正在运行的进程(不需要重启!)
python -m profiling.sampling --attach 12345

# 四种采样模式
python -m profiling.sampling --mode wall your_script.py    # 墙钟时间(含 I/O 等待)
python -m profiling.sampling --mode cpu your_script.py     # 纯 CPU 时间
python -m profiling.sampling --mode gil your_script.py     # GIL 持有时间
python -m profiling.sampling --mode exception your_script.py  # 异常线程采样

输出格式也覆盖了主流生态:

# 生成可交互的 HTML flame graph
python -m profiling.sampling --flamegraph output.html your_script.py

# pstats 兼容格式
python -m profiling.sampling --pstats output.prof your_script.py

# Firefox Profiler 格式
python -m profiling.sampling --gecko output.json your_script.py

# 源码行级 heatmap
python -m profiling.sampling --heatmap output.html your_script.py

# 实时 TUI(top-like 界面)
python -m profiling.sampling --live your_script.py

对 async 代码有 --async-aware 标志,会把异步任务的调用栈正确重建出来——以前的 profiler 面对 asyncio 代码基本抓瞎。

跟你有什么关系:如果你的 Python 服务有性能问题,以前你可能靠 print(time.time()) 排查。现在一行命令 attach 到生产进程,30 秒后拿到 flame graph。3.15 之前这是做不到的。

Frame pointers 默认开启

这个改动对普通用户不可见,但很重要。

CPython 3.15 在编译时默认开启了 frame pointers(-fno-omit-frame-pointer)。这意味着系统级的 profiler(perf、eBPF 工具、调试器)可以正确展开 Python 的调用栈——以前混合 C 扩展和 Python 代码的栈追踪经常断裂或不完整。

对于用 eBPF 做性能可观测性的团队,这是一个很大的改进。


05⚠️ L3 进阶区:生态地基的三个底层变化

以下内容偏底层。如果你只关心"能不能升级、怎么升级",跳到下一节就行。

UTF-8 成为默认编码

Python 3.15 开始,open('file.txt') 默认用 UTF-8 编码,不再依赖操作系统的 locale 设置。这意味着:

  • macOS 上 open('file.txt').read() 不会因为 locale 是 C 而在非 ASCII 字符上报错
  • Linux 服务器上用 Docker 跑 Python,不会再出现 UnicodeDecodeError 因为容器里 locale 没配
  • 跨平台脚本的行为终于一致了

需要恢复旧行为的,两个途径:

export PYTHONUTF8=0
# 或
python -X utf8=0 your_script.py

单个文件级:open('file.txt', encoding='locale')

GC 回退:3.14 的增量 GC 被撤回了

Python 3.14 引入了一个新的增量垃圾回收器,目标是降低 GC 暂停时间。但多个生产环境用户报告了"显著的内存压力"(CPython issue gh-142516)。于是核心团队做了一个成熟的决定:在 3.14.5 和 3.15 中回退到 3.13 的分代 GC。

这不是失败——这是一个 34 岁语言的核心团队在说"稳定性比新特性重要"。增量 GC 可能经过正式的 PEP 流程后在 3.16 回归。

对你的影响:如果你在 3.14.0-3.14.4 上跑生产,立刻升到 3.14.5+ 或直接跳到 3.15。如果你在 3.13 以下,不用管这事。

.start 文件替代 .pth 的 import hack

.pth 文件可以往 sys.path 加路径,但有个历史遗留功能——import 行会在 Python 启动时执行。这个功能一直被滥用,安全风险很大。

3.15 引入了 .start 文件,用明确的入口点格式 pkg.mod:callable 替代。同时 .pth 中的 import 行被静默废弃。

如果你的项目用了 .pth 文件做启动时初始化——该迁移了。


06数据工程师的 3.15 迁移指南

别急着  pip install --upgrade。按这个步骤来:

第一步:本地安装测试版

pyenv install 3.15.0b2
pyenv local 3.15.0b2
pip install -r requirements.txt  # 看有没有装不上的包
pytest  # 跑一遍测试

哪些项目可以现在就开始测

  • 纯 Python 的 CLI 工具和脚本——直接跑,大概率没问题
  • 数据处理 pipeline(Pandas/Polars)——JIT 加速白捡的
  • asyncio 应用——Tachyon profiler 的 async-aware 模式值得一试

哪些项目等到 10 月正式版

  • 依赖 C 扩展的项目(等生态适配)
  • 生产环境 API 服务(第一个 beta 不建议)
  • 依赖特定 3.14 GC 行为的项目(3.15 回退了,行为不同)

第二步:CI 配置

# GitHub Actions
jobs:
  test:
    strategy:
      matrix:
        python-version: ["3.13""3.15.0-beta.2"]
    steps:
      uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}

先在 CI 矩阵里加上 3.15 做 canary——允许失败,但能提前发现问题。

第三步:lazy import 渐进式迁移

提升启动速度最容易的切入点:

# 在 __init__.py 或入口模块顶部
__lazy_modules__ = [
    "heavy_parser",
    "report_generator",
    "email_sender",
]

这行代码在 3.15 以下版本被忽略,在 3.15+ 自动生效——零风险,渐进式。找一个 import 重但使用少的模块开始试。


07Python 的工程化成人礼

回顾 Python 最近三年的版本轨迹:

  • 3.12(2023)→ 类型系统大年:泛型语法简化(PEP 695)、override 装饰器
  • 3.13(2024)→ 性能元年:JIT 编译器首次引入、GIL 变为可选
  • 3.14(2025)→ GC 尝试重写……然后撤回
  • 3.15(2026)→ 静默补齐:懒加载、不可变映射、profiler 原生化、编码统一

趋势很清晰:Python 不再需要通过"大功能"证明自己的生命力。它在做一件更难的事——把散布在生态里被验证了十年、二十年的最佳实践,一个一个收进语言核心

frozendict 收了 types.MappingProxyType 和无数个"用 tuple(sorted(d.items())) 假装不可变 dict"的 workaround。lazy import 收了 importlib.util.LazyLoader 和各框架自己造的懒加载轮子。Tachyon 收了 py-spyaustinscalene 这些第三方 profiler 的需求。

这个"回收"过程不如新语法热闹,但它回答了一个更根本的问题:怎么让 Python 在下一个十年仍然是"对的选择"。答案不是变成 Rust,也不是变成 Go,而是——变得更快、更可观测、更可预测。

3.14 那波增量 GC 我差点在线上开了——还好看到 GitHub issue 的 memory pressure 报告后踩了刹车。这是我第一次因为"观望"而庆幸的版本升级。

收进标准库是一回事,第三方会不会跟进是另一回事。frozendict 很好,但 Django ORM 和 SQLAlchemy 什么时候不再用 isinstance(x, dict) 做类型检查?生态适配才是真正的瓶颈。

3.15 完成这一步的方式很 Python:不激进,不破坏,把正确的东西默默做好。

我打算拿一个内部的 CLI 工具开刀——它 import 了 20 个模块但每个子命令只用 2 个。__lazy_modules__ 加一行,不改逻辑,启动时间能减多少我自己也很好奇。


08升级检查清单

把下面这个存成 python315_checklist.md,升级时对照:

## Python 3.15 升级检查清单

### 安装
- [ ] pyenv install 3.15.0b2
- [ ] pip install -r requirements.txt(记录装不上的包)
- [ ] pytest / 项目测试套件(记录失败的 case)

### 代码适配
- [ ] isinstance(x, dict) → isinstance(x, (dict, frozendict)) 或 collections.abc.Mapping
- [ ] open() 不带 encoding 的调用——行为从 locale 编码变为 UTF-8,确认无影响
- [ ] .pth 文件中的 import 行 → 迁移到 .start 文件
- [ ] 如有自定义 lazy import filter,配置 sys.set_lazy_imports_filter()

### 性能验证
- [ ] 用 Tachyon 跑一次采样:python -m profiling.sampling --flamegraph perf.html main.py
- [ ] 对比 3.14 vs 3.15 的端到端执行时间
- [ ] 如有 asyncio 代码,加 --async-aware 标志验证任务栈

### 生产部署
- [ ] 等待 3.15.0 正式版(2026-10-01)
- [ ] CI 矩阵加 3.15
- [ ] 灰度发布:先 10% 流量

1、推荐 4 个 Star 数不高但挺有趣的 GitHub 项目。

2、 线程池明明还有最大线程闲着,为什么任务非要进队列排队?

3、别再用HTTP调用大模型了,大厂都在用Spring AI?

4、从 kimi-cli 用 TypeScript 重构说起:为什么大家都在拥抱 TypeScript?

5、别再当AI "善后工程师" 了,AI 真的可以帮你写好代码

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/197243