python 3.12 彻底移除 distutils 模块,导致 import、setup.py 构建及依赖包(如 numpy

ModuleNotFoundError: No module named 'distutils' 是硬删除,不是警告
Python 3.12 真的把 distutils 从源码里删干净了——不是弃用、不发警告、也不留 stub。任何代码里出现 import distutils、from distutils.core import setup 或 from distutils.version import LooseVersion,解释器启动时就炸,没商量。
这不是 pip 版本低或网络问题,而是你连模块名都找不到。PyPI 上那个叫 distutils 的包是空壳,装了也没用;pip install setuptools 能缓解部分构建场景,但它不提供 distutils.cmd.Command 这类底层类,旧 setup.py 里继承它的自定义命令照样崩。
- CI 构建卡在
Preparing metadata (setup.py):pip 检测到没pyproject.toml,又不敢执行已消失的distutils,于是死循环 - Docker 镜像用
FROM python:3.12-slim后直接pip install -r requirements.txt失败:环境里压根没预装setuptools - PyCharm 新建虚拟环境后右键 “Install package” 报错:IDE 内部仍走传统安装路径,没强制启用 PEP 517
旧项目依赖链里藏着 distutils,不报错也危险
你自己的代码可能没写 distutils,但依赖包可能偷偷用了。比如 APLpy 在 <code>aplpy/core.py 里调 distutils.version 做版本比较;numpy 的 <code>setup.py 依赖 numpy.distutils 构建 C 扩展;torchvision 的 <code>build_ext 类继承自 distutils.command.build_ext。
这些调用在 Python 3.11 及之前能跑,是因为 distutils 还在。到了 3.12,它们要么当场报错,要么静默失效——比如 distutils.dir_util.copy_tree() 和 shutil.copytree(..., symlinks=True) 行为不一致,部署时才发现文件没拷对。
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
-
from distutils.version import LooseVersion→ 必须换成from packaging.version import parse,否则"1.2.0a1" > "1.2.0"判断结果相反 -
setup.py里继承distutils.command.build_ext→ 得改成setuptools.command.build_ext.build_ext,否则实例化就AttributeError - 混用
numpy.distutils的项目(如老版 scikit-image)→ 升级numpy>=1.26不够,还得换构建系统,比如meson或pybind11
pyproject.toml 缺失或写错,pip 就不会接管构建
PEP 517 规定:只要项目根目录有 pyproject.toml,pip 就必须忽略 setup.py,只按 [build-system] 段指定的后端(如 setuptools 或 hatchling)来构建。但如果这个文件缺失、语法错误,或者声明的后端没装(比如写了 requires = ["hatchling"] 却没 pip install hatchling),pip 就会 fallback 到传统路径——然后撞上消失的 distutils。
很多旧项目只有 setup.py,没 pyproject.toml,等于主动放弃 PEP 517。此时 pip 3.12+ 会尝试包装 setup.py,但包装链里仍要调 distutils,结果还是崩。
- 最简补救:新建
pyproject.toml,内容只需两行:[build-system]和requires = ["setuptools>=45", "wheel"] - 别写
build-backend = "setuptools.build_meta":新版setuptools默认就是它,显式写反而容易因版本不匹配出错 - 如果项目用
setup.cfg配置元数据,确保pyproject.toml里没重复声明project段,否则 pip 会优先读 TOML,忽略 CFG
某些包根本没适配 Python 3.12,硬装会埋 runtime 坑
装成功 ≠ 能用。比如旧版 torchvision()在 Python 3.12 下即使绕过构建失败(比如用 <code>--no-build-isolation 强装),运行时也会挂:调用 torchvision::nms 报 RuntimeError: operator torchvision::nms does not exist,因为它的二进制扩展是按 Python 3.11 ABI 编译的,3.12 修改了 PyTypeObject 初始化逻辑,符号根本加载不上。
conda 安装更隐蔽:它可能跳过冲突、降级其他包,让你以为 import torch 成功了,直到 torch.randn(10).cuda() 触发 segmentation fault 或 OSError: [WinError 1114]。
- 查 wheel 标签:PyPI 上旧
torchvision的文件名含cp311,不含cp312—— pip 根本不会选它 - 别信
pip install --force-reinstall:它不解决 ABI 不兼容,只是覆盖已装文件 - 真要跑旧模型,用
pyenv或conda env隔离 Python 3.11 环境,比硬塞 3.12 更稳
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










