python 3.12 彻底移除 distutils,必须迁移到 setuptools 或标准库替代方案;需检查隐式依赖、改用 pyproject.toml(build-backend="setuptools.build_meta")、替换 distutils 功能为 shutil/platform/sysconfig 等,并升级或规避遗留第三方包。

Python 3.12 中 distutils 已被彻底移除,任何直接 import 或间接依赖它的代码都会报 ModuleNotFoundError: No module named 'distutils' —— 不能靠降级或打补丁绕过,必须迁移到 setuptools 或标准库替代方案。
检查你的项目是否隐式依赖 distutils
很多老项目没显式写 import distutils,但可能通过以下方式间接触发:
-
setup.py中继承了distutils.core.Command或调用了distutils.util.convert_path() - 使用了已废弃的
python setup.py install流程(而非pip install .) - 第三方包(如旧版
numpy、scipy、py2exe)在构建时调用了distutils -
pyproject.toml中未声明构建后端,导致 pip 回退到默认的distutils兼容逻辑
运行 python -c "import setuptools; print(setuptools.__version__)" 确保你用的是 setuptools >= 61.0.0(支持 PEP 517/518),再检查 pyproject.toml 是否存在且包含有效构建配置。
用 pyproject.toml 替代 setup.py(强制走 PEP 517 构建)
这是最干净的解法:完全弃用 setup.py,让构建过程不经过 distutils 路径。
最小可用 pyproject.toml 示例:
[build-system] requires = ["setuptools>=61.0", "wheel"] build-backend = "setuptools.build_meta" [project] name = "my-package" version = "0.1.0"
关键点:
-
build-backend = "setuptools.build_meta"指向现代构建入口,不碰distutils - 如果项目有 C 扩展,改用
setuptools.Extension而非distutils.core.Extension - 不要留空的
setup.py文件 —— 它会干扰 PEP 517 检测,删掉或重命名为setup.py.backup
替换 distutils 中常用功能的具体写法
常见迁移对照:
-
distutils.util.get_platform()→ 改用import platform; platform.machine() + '-' + platform.system().lower()(注意:这仅作标识参考,真实平台判断应依赖sysconfig.get_platform()) -
distutils.dir_util.copy_tree()→ 改用shutil.copytree(src, dst, dirs_exist_ok=True)(Python 3.8+) -
distutils.file_util.copy_file()→ 改用shutil.copy2()或shutil.copy() -
distutils.spawn.find_executable()→ 改用shutil.which() - 自定义命令类(如
build_ext子类)→ 继承setuptools.command.build_ext.build_ext,不是distutils.command.build_ext.build_ext
特别注意:sysconfig.get_config_vars() 可替代大部分 distutils.sysconfig 的读取需求,但变量名可能略有差异(例如 LIBDIR → LIBDIR 仍可用,但 INSTALL_SCHEMES 已不存在)。
处理遗留第三方包的兼容问题
如果你无法控制依赖包(比如某个私有包还在用 setup.py 且未更新),临时缓解方案有限:
- 升级该包到最新版 —— 多数主流包(
numpy、scipy、matplotlib)已在 2023 年底前完成迁移 - 若必须用旧版,可尝试加环境变量
SETUPTOOLS_USE_DISTUTILS=local(仅对 setuptools 64.0.0–67.8.0 有效,且 Python 3.12 不支持) - 更现实的做法:用
pip install --no-build-isolation -e .跳过隔离构建,前提是你的本地环境已预装兼容版本的构建依赖
真正棘手的是那些硬编码调用 distutils.cmd.Command 的私有构建脚本 —— 它们必须重写,没有“兼容层”可依赖。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











