python 3.12依pep 594物理删除distutils、imp及pkgutil.impimporter等“死电池”模块,import即报错无警告;需用importlib替代imp、pyproject.toml替代setup.py、ensurepip升级pip至≥23.3。

distutils、imp、pkgutil.ImpImporter 这些模块不是“意外消失”,而是被物理删除——Python 3.12 执行了 PEP 594 的清理决议,把长期弃用、无人维护、有更优替代的模块从源码中彻底移除。你代码里只要写了 import distutils 或 from pkgutil import ImpImporter,运行时就直接报 ModuleNotFoundError 或 AttributeError,没有警告,不给绕过机会。
为什么 import distutils 会直接失败?
因为 distutils 不再是标准库的一部分:它的所有 .py 文件已从 CPython 源码树中删除,sys.stdlib_module_names 里也查不到它。旧项目若还在用 python setup.py build,或隐式依赖 distutils.version.LooseVersion,就会立刻中断。
-
distutils.core、distutils.util、distutils.dir_util全部不可 import -
setuptools本身不提供distutils模块,只在运行时动态注册部分命令(如build_ext),但不会恢复import distutils - 别试
pip install python3-distutils—— 这个包只适配系统 Python(比如 Ubuntu 的 3.10),和你的 3.12 环境 ABI 不兼容
为什么 pkgutil.ImpImporter 报错会让 pip 罢工?
Python 3.12 内置的 pip(通常是 22.x)仍硬编码调用 pkgutil.ImpImporter,而该属性已被删。结果就是:连 pip install --upgrade pip 都执行不了——它需要 pip 来升级 pip,但 pip 自己启动就崩。
- 根本解法是绕过 pip 本身:用
python -m ensurepip --upgrade,这个命令不依赖现有 pip,直接从标准库拉取兼容版本 - 确保升级后
python -m pip --version输出的是 ≥23.3 的 pip,否则仍有风险 - 顺手跑
python -m pip install --upgrade setuptools wheel,避免pkg_resources相关问题(比如ModuleNotFoundError: No module named 'pkg_resources')
为什么 imp.load_source() 替换起来容易出错?
表面看只是把 imp.load_source('m', '/path/to/m.py') 换成 importlib.util.spec_from_file_location(),但实际行为差异藏得深:
-
imp.load_source()会无条件执行模块顶层代码;spec.loader.exec_module()要求 spec 有效且 loader 存在,否则静默失败 - 若文件路径含非 ASCII 字符或符号链接,
importlib.util.spec_from_file_location()可能返回None,必须加判空 - 旧代码里用
imp.find_module()查找插件路径?现在得用importlib.util.find_spec(name, package=None),它返回ModuleSpec,不直接给路径——要取spec.origin或spec.submodule_search_locations
distutils.dir_util.copy_tree() 和 shutil.copytree(..., symlinks=True) 对符号链接的递归策略不同,或者 numpy.distutils 在构建 C 扩展时与 setuptools 的 ABI 不一致——这些不会报错,但会在打包后运行时崩溃。Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











