Skip to content

Python 3.15 安装与升级指南:用 uv 安装、延迟导入提速、数据科学库兼容性实测

更新于

用一条 uv 命令安装 Python 3.15,再实测 numpy、pandas、PyTorch、DuckDB、Polars 能不能装上。macOS 实测:wheel 兼容性表、延迟导入 (lazy import) 把脚本启动从 2.7 s 降到 0.01 s、lazy import 报 SyntaxError 的三种写法、UTF-8 默认编码对 GBK 文件的影响,以及自由线程版本。

先说结论: Python 3.15.0 已于 2026 年 10 月 9 日正式发布。如果你用 uv (opens in a new tab),先升级 uv,再安装:

uv self update
uv python install 3.15

然后新建一个测试项目,用你真实的依赖试一遍,确认没问题再迁移重要项目:

uv init --python 3.15 py315-test
cd py315-test
uv add numpy pandas scikit-learn matplotlib

常用的科学计算库目前都有现成的 wheel,可以直接装。PyTorch 和 TensorFlow 还装不上。 DuckDB 需要从源码编译。如果你的项目依赖其中任何一个,先留在 3.14(uv python pin 3.14)。

最值得为之升级的新特性是延迟导入(lazy import)。只加一个关键字,写成 lazy import pandas as pd,测试脚本的 --help 路径就从 2.7 秒降到了 0.01 秒。

测试说明: 下文标注"实测"的内容,均于 2026 年 10 月 11 日在 Apple M4 Max(macOS)上完成,使用 uv 0.13.0,以及通过 uv python install 安装的 CPython 3.15.0 / 3.15.0t。Windows 和 Linux 上的行为、python.org 安装包、pyenv 和 conda 的内容来自官方文档,没有实测。

3.15 里你会实际碰到的变化

更新日志很长。如果你写数据脚本或命令行工具,下面这五项最可能遇到:

变化对你的影响怎么做
延迟导入(PEP 810)lazy import x 会推迟到第一次使用时才加载模块用在命令行工具、脚本和启动慢的应用里
默认编码改为 UTF-8(PEP 686)open("file.txt") 在所有系统上都按 UTF-8 读写Windows 用户如果有 GBK / cp1252 / cp932 文件,要显式传 encoding=
uv 0.13 默认使用 3.15没有固定版本的新 uv 项目会自动用 3.15依赖还没跟上的项目,固定到 3.14
自由线程版本有了稳定 ABI(PEP 803)python3.15t 可以真正并行跑线程,但大多数包还没有为它发布稳定 ABI 的 wheel在 3.15t 上做好从源码编译的准备
新增 frozendict、sentinel 内置类型和 profiling 包新的内置类型,以及 Tachyon 采样分析器可选;不用它们也不会出问题

完整列表见 官方 What's New in Python 3.15 (opens in a new tab)。本文后面只讲要动手做的事:安装、检查兼容性、使用延迟导入、处理编码变化,以及要不要用自由线程版本。

第 1 步:安装 Python 3.15

用 uv 安装(实测)

安装前先更新 uv。 这是这周最容易犯的错。旧版 uv 只认识 alpha 版本。我们原来装的 uv 0.9.25 上,uv python list 3.15 只显示 cpython-3.15.0a4。这时运行 uv python install 3.15,装上的是 alpha,不是正式版。

uv self update          # 需要 0.13.0 或更高版本
uv --version
uv python install 3.15

uv 0.13.0 用 24.8 秒装好了普通版和自由线程版:

uv python install 3.15 3.15t
Installed 2 versions in 24.83s
 + cpython-3.15.0+freethreaded-macos-aarch64-none (python3.15t)
 + cpython-3.15.0-macos-aarch64-none (python3.15)

如果你是用 Homebrew、pip 或 pipx 装的 uv,uv self update 不起作用。用原来的安装方式升级(brew upgrade uv、pipx upgrade uv)。

uv 0.13 还改了默认版本。uv 0.13.0 发布说明 (opens in a new tab) 写明,不带版本号的 uv python install 现在会下载 3.15。新建 uv venv 或运行 uvx python 时,如果本机没有兼容的 Python,也会下载 3.15。已安装的版本仍会被使用。要让某个项目留在 3.14,把版本记下来:

uv python pin 3.14

这条命令会写入 .python-version,uv 每次在这个目录运行时都会读取它。

其他安装方式(来自官方文档,未实测)

  • python.org 安装包(Windows、macOS):从 python.org/downloads (opens in a new tab) 下载 3.15.0。按发布说明,官方 macOS 安装包现在默认会安装自由线程支持,Windows 64 位版本使用新的尾调用解释器。
  • pyenv:先 pyenv update,再 pyenv install 3.15.0。要等你的 pyenv 版本能列出 3.15.0。
  • conda:等 conda-forge 发布之后,用 python=3.15 创建环境。规划迁移前先确认它已经发布。

如果想了解在各个系统上切换 Python 版本的通用做法,我们以前写的 Python 升级指南和 Python 版本管理工具对比仍然适用。本文只讲 3.15 特有的部分。

第 2 步:检查你的包能不能装上

这一步决定你今天能不能升级。我们新建了一个干净的 3.15 项目,装了一套典型的数据科学依赖,再去 PyPI 查了大家最常问的几个包。

兼容性表(2026 年 10 月 11 日实测)

包(版本)Python 3.15Python 3.15t(自由线程)备注
numpy 2.5.4WheelWheel
pandas 3.0.6WheelWheel
scipy 1.18.1WheelWheel
scikit-learn 1.9.1WheelWheel
matplotlib 3.11.2WheelWheel
pyarrow 26.0.0WheelWheel
polars 2.0.0Wheel (abi3)从源码编译它的运行时只发布 cp310-abi3 wheel,自由线程 Python 用不了。Rust 编译耗时 6 分 51 秒
ipykernel 9.17.1(pyzmq、psutil、debugpy)Wheel未测试Jupyter 内核可以在 3.15 上运行
duckdb 1.5.6从源码编译未测试wheel 只到 cp314。C++ 编译约 2.5 分钟
pygwalker 0.5.0.1可用未测试依赖 duckdb,所以也要经历源码编译
torch 2.14.1无法安装无法安装wheel 只有 cp310 到 cp314 和 cp314t
tensorflow 2.21.0无法安装无法安装wheel 只有 cp310 到 cp313

在 3.15 上安装 numpy、pandas、scipy、scikit-learn、matplotlib、pyarrow 和 polars,连下载一共 71 秒,全程无需编译。同一组包在 3.15t 上用了 6 分 51 秒,几乎全花在编译 Polars 上。

某个包没有 wheel 时,uv 会明确告诉你原因。下面是 PyTorch 在 3.15 上的提示:

hint: You require CPython 3.15 (`cp315`), but we only found wheels for `torch`
(v2.14.1) with the following Python ABI tags: `cp310`, `cp311`, `cp312`, `cp313`, `cp314`, `cp314t`

一分钟检查你自己的项目

不需要真的安装。对一个 3.15 环境做一次试运行(dry run)就行:

uv venv --python 3.15 .venv315
uv pip install --dry-run --python .venv315/bin/python -r requirements.txt

能解析成功就没问题。如果看到上面那种 cp315 提示,那个包就是阻碍你升级的原因。

从源码编译不算失败,但很慢,还需要编译器(Polars 要 Rust,DuckDB 要 C++)。在 CI 里,源码编译可能把一分钟的任务拖成十分钟。在 wheel 发布之前,CI 里先固定 3.14。

第 3 步:用延迟导入让脚本启动更快

我认为延迟导入是升级到 3.15 最好的理由。它解决的问题大家都熟悉。

命令行脚本通常在文件顶部导入所有东西。哪怕只运行 my_tool.py --help,也要付出加载 pandas、matplotlib 和 scikit-learn 的全部代价,尽管根本用不到它们。

改前改后对比(实测)

普通(立即导入)版本:

import sys
import pandas as pd
import matplotlib.pyplot as plt
import sklearn.linear_model
 
if len(sys.argv) > 1 and sys.argv[1] == "--help":
    print("usage: tool [--help] file.csv")
    sys.exit(0)

延迟导入版本只多了 lazy 关键字:

import sys
lazy import pandas as pd
lazy import matplotlib.pyplot as plt
lazy from sklearn import linear_model
 
if len(sys.argv) > 1 and sys.argv[1] == "--help":
    print("usage: tool [--help] file.csv")
    sys.exit(0)
 
df = pd.DataFrame({"x": [1, 2, 3], "y": [2, 4, 6]})
model = linear_model.LinearRegression().fit(df[["x"]], df["y"])
print(model.coef_)

在我们的机器上,python script.py --help 各跑五次的结果:

版本耗时-X importtime 输出行数
立即导入2.69 到 2.74 s1,747
lazy import0.01 s27

完整的代码路径照样能跑:延迟导入版本拟合了回归模型,输出 2.0。pandas 在第一次用到 pd 的那一行才加载。

你的绝对数字会不一样。在这个环境里,单独 import sklearn.linear_model 就要 2.2 s,import pandas 要 0.86 s。只要程序的某个分支不碰重型库,这个规律就成立。

看看延迟导入在做什么

延迟导入的名字在被使用之前只是一个代理对象。你可以直接看到:

import sys
lazy import json
 
print(type(globals()["json"]))   # <class 'lazy_import'>
print("json" in sys.modules)     # False
json.dumps(1)
print(type(globals()["json"]), "json" in sys.modules)   # <class 'module'> True

想先找出哪些导入慢,运行 python -X importtime your_script.py 2> imports.log,再按第二列排序。

lazy 会报 SyntaxError 的三种写法(实测)

lazy 只能用在模块顶层。下面三种错误我们都遇到了:

位置报错信息
函数内部SyntaxError: lazy import not allowed inside functions
try / except 内部SyntaxError: lazy import not allowed inside try/except blocks
星号导入SyntaxError: lazy from ... import * is not allowed

其中 try/except 这条影响最大。像 try: import ujson as json except ImportError: import json 这样的代码没法改成延迟导入。要么让这段回退逻辑保持立即导入,要么把它挪到一个小模块里,再延迟导入那个模块。

官方文档还提到,类定义体内的导入和 from __future__ 导入也不能延迟。

报错会推迟到第一次使用

缺失的模块不会再在文件顶部报错:

lazy import not_a_real_module
print("defined ok")          # 这一行会正常输出
not_a_real_module.x          # 在这里才抛出 ModuleNotFoundError

这对可选依赖很方便。但这也意味着,导入语句里的拼写错误可能一直藏着,直到某个很少走到的代码路径运行时才暴露。每个延迟导入至少要有一个测试覆盖到。

不改代码,让所有导入都变成延迟导入

可以在命令行里把整个程序切换成延迟导入:

python -X lazy_imports=all my_tool.py --help
# or
PYTHON_LAZY_IMPORTS=all python my_tool.py --help

我们没改过的立即导入脚本,用这种方式也降到了 0.01 s。但要小心那些在导入时就执行操作的模块。我们写了一个很小的插件模块,导入时会打印信息并注册自己。用了 lazy_imports=all 之后,注册根本没执行,因为程序从来没用到这个模块的名字:

normal:   plugin registered / main done
all:      main done

在导入时注册插件、编解码器或 matplotlib 后端的库,都可能这样出问题。用 =all 来估算能省多少时间,然后只给你确认安全的导入手动加上 lazy。需要更细的控制,可以看文档里的 sys.set_lazy_imports_filter()。

同一份代码同时支持 3.14 和 3.15

lazy 关键字在 3.14 及更早版本里是语法错误。如果代码要在两个版本上都能跑,改用模块级的 __lazy_modules__ 列表。旧版本会忽略它,3.15 会把列表里的导入当作延迟导入:

__lazy_modules__ = ["pandas"]
 
import sys
import pandas as pd          # 3.15 上延迟导入,3.14 上立即导入
 
print("pandas" in sys.modules)   # 3.15 上在用到 pd 之前为 False

我们确认过,用这种写法时,3.15 上的 pandas 不会出现在 sys.modules 里。

第 4 步:处理 UTF-8 默认编码

在 3.15 上,不带 encoding 参数的 open() 在所有平台上都使用 UTF-8。我们确认默认情况下 sys.flags.utf8_mode == 1,设置 PYTHONUTF8=0 后为 0。

在 macOS 和 Linux 上,这几乎没有影响。在 Windows 上,所有不指定编码读取旧文件的代码都会受影响:中文 GBK 文件、cp1252 编码的 Excel CSV 导出、日文 Shift-JIS(cp932)文件。读取这些文件现在可能抛出 UnicodeDecodeError,或者读出乱码。中文 Windows 用户最常遇到的就是 GBK 编码的 CSV 和文本文件。

解决办法是把编码写明。下面的例子用的是 cp932,GBK 文件把它换成 encoding="gbk" 即可:

import pandas as pd
 
df = pd.read_csv("export.csv", encoding="cp932")      # 日文 Excel 导出文件
with open("legacy.txt", encoding="locale") as f:      # 旧行为:使用系统区域编码
    text = f.read()

升级前想找出受影响的代码,可以在当前的 Python 上加 -X warn_default_encoding 跑一遍测试。想临时恢复旧行为,设置 PYTHONUTF8=0。

第 5 步:要不要用自由线程版本(3.15t)

自由线程 Python 去掉了 GIL,纯 Python 线程可以用上多个 CPU 核心。我们把一个 CPU 密集型循环跑了四次,先顺序执行,再用四个线程执行:

版本顺序执行4 线程加速比
Python 3.150.72 s0.71 s1.0×
Python 3.15t0.65 s0.19 s3.4×

导入 numpy、pandas、scikit-learn、polars、matplotlib 和 pyarrow 之后,GIL 仍然保持关闭(sys._is_gil_enabled() 返回 False)。

如果你在线程里跑 CPU 密集的纯 Python 代码,并且依赖都有 cp315t wheel,就用 3.15t。如果依赖 Polars、DuckDB 或深度学习库,先别用。如果繁重的计算本来就在 NumPy 或 pandas 内部完成,也不需要它,这些库自己会释放 GIL。

现在该不该升级?

你的情况建议
使用 numpy / pandas / sklearn 的脚本、命令行工具、自动化任务升级。 延迟导入的收益很实在
用 Jupyter notebook 做分析在新环境里升级;旧内核再保留几周
PyTorch 或 TensorFlow 项目留在 3.14(uv python pin 3.14)
CI 里用 DuckDB,或在 3.15t 上用 Polars等 wheel 发布,或者接受编译耗时并在 CI 里装好编译器
Windows 上读取旧编码文件的代码先加上显式的 encoding=,再升级

在 Jupyter 里使用 3.15

ipykernel 可以在 3.15 上安装和运行。从 uv 项目注册一个 3.15 内核:

uv add ipykernel
uv run python -m ipykernel install --user --name py315 --display-name "Python 3.15"

如果你常用 notebook,RunCell (opens in a new tab) 是运行在 Jupyter 里的 AI 智能体,能看到你内核的实时状态。测试旧 notebook 在新内核上还能不能跑时,这一点很有用。PyGWalker (opens in a new tab) 也能在 3.15 上运行(实测:pyg.to_html() 成功渲染了一个 DataFrame),只是要经历上面提到的 DuckDB 编译。

常见问题排查

现象原因解决方法
uv python install 3.15 装上的是 3.15.0a4uv 版本低于 0.13uv self update,或通过 Homebrew / pipx 升级
No solution found … no wheels with a matching Python ABI tag (cp315)这个包还没有 3.15 的 wheel(torch、tensorflow)对该项目执行 uv python pin 3.14
安装 duckdb 或 polars-runtime 时卡住好几分钟没有匹配的 wheel,正在从源码编译耐心等待(需要 C++ 或 Rust 编译器),或改用 3.14 / 普通版 3.15 代替 3.15t
SyntaxError: lazy import not allowed …lazy 写在了函数、try 或类里把导入移到模块顶层,或保持立即导入
某个插件或后端不再注册-X lazy_imports=all 跳过了带副作用的导入去掉 =all;只在挑选过的导入上使用 lazy
升级后 Windows 上出现 UnicodeDecodeError默认编码改成了 UTF-8传入 encoding="cp1252" / "cp932" / "gbk" 或 encoding="locale"
新建的 uv 项目意外用上了 3.15uv 0.13 改了默认版本uv python pin 3.14
某个依赖报 SyntaxWarning: 'return' in a 'finally' block该库的旧代码被新版 Python 标记出来无害;警告来自库本身,不是你的代码

常见问题

Python 3.15 什么时候发布的? Python 3.15.0 于 2026 年 10 月 9 日发布。

怎么用 uv 安装 Python 3.15? 先把 uv 升级到 0.13.0 或更高版本,再运行 uv python install 3.15。旧版 uv 只认识 3.15 的 alpha 版本。

pandas 能在 Python 3.15 上用吗? 能。pandas 3.0.6 提供 cp315 和 cp315t wheel,numpy、scipy、scikit-learn、matplotlib 和 pyarrow 也一样。

PyTorch 支持 Python 3.15 吗? 还不支持。截至 2026 年 10 月 11 日,torch 2.14.1 的 wheel 最高只到 cp314 和 cp314t,所以没法在 3.15 上安装。

Python 3.15 的延迟导入是什么? 写成 lazy import module 后,Python 会先创建一个轻量的代理对象,等这个名字第一次被使用时才加载模块。用不到该模块的代码路径,启动时间会大幅缩短。

用了延迟导入还能兼容 Python 3.14 吗? 能。在模块顶部定义 __lazy_modules__ = ["module_name"]。Python 3.15 会把这些导入当作延迟导入,旧版本会忽略这个列表。

怎么让项目继续使用 Python 3.14? 在项目目录下运行 uv python pin 3.14。它会写入一个 .python-version 文件,uv 会遵循它。

相关指南