Python3.12下PyInstaller编译二进制文件时setuptools导入报错
Python3.12 + PyInstaller打包后运行报
KeyError: 'setuptools._distutils.compilers'的解决方案 问题现象
使用PyInstaller打包Python3.12项目后,运行二进制文件触发以下错误:
File "buildpackage.py", line 38, in <module> File "<frozen importlib._bootstrap>", line 1354, in _find_and_load File "<frozen importlib._bootstrap>", line 1325, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 929, in _load_unlocked File "PyInstaller/loader/pyimod02_importers.py", line 419, in exec_module File "package/package.py", line 24, in <module> File "<frozen importlib._bootstrap>", line 1354, in _find_and_load File "<frozen importlib._bootstrap>", line 1325, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 929, in _load_unlocked File "PyInstaller/loader/pyimod02_importers.py", line 419, in exec_module File "setuptools/_distutils/dir_util.py", line 10, in <module> File "<frozen importlib._bootstrap>", line 1409, in _handle_fromlist File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed File "<frozen importlib._bootstrap>", line 1354, in _find_and_load File "<frozen importlib._bootstrap>", line 1325, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 929, in _load_unlocked File "PyInstaller/loader/pyimod02_importers.py", line 419, in exec_module File "setuptools/_distutils/file_util.py", line 9, in <module> File "<frozen importlib._bootstrap>", line 1354, in _find_and_load File "<frozen importlib._bootstrap>", line 1325, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 929, in _load_unlocked File "PyInstaller/loader/pyimod02_importers.py", line 419, in exec_module File "setuptools/_distutils/errors.py", line 9, in <module> File "<frozen importlib._bootstrap>", line 1354, in _find_and_load File "<frozen importlib._bootstrap>", line 1304, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed File "<frozen importlib._bootstrap>", line 1354, in _find_and_load File "<frozen importlib._bootstrap>", line 1316, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 1256, in _find_spec File "PyInstaller/loader/pyimod02_importers.py", line 312, in find_spec File "<frozen importlib._bootstrap_external>", line 1334, in __init__ File "<frozen importlib._bootstrap_external>", line 1350, in _get_parent_path KeyError: 'setuptools._distutils.compilers'
关键疑问解答
1. setuptools._distutils.compilers及其子目录缺__init__.py是否正常?
正常。Python3.3+支持命名空间包,无需__init__.py即可将目录识别为包。新版setuptools(适配Python3.12的版本)采用了这种结构,但PyInstaller的打包逻辑对无__init__.py的命名空间包存在兼容性缺陷,导致打包时无法正确解析路径结构,运行时触发KeyError。
2. 为什么--hidden-import无效?
--hidden-import仅告诉PyInstaller要包含指定模块,但无法修复PyInstaller对命名空间包路径解析的底层问题——即使强制导入模块,路径结构缺失仍会导致KeyError。
正规修复方案
方案1:使用PyInstaller自定义Hook(推荐)
这是PyInstaller官方推荐的扩展方式,无需修改依赖包本身:
- 创建
hook-setuptools._distutils.py文件,内容如下:
from PyInstaller.utils.hooks import collect_submodules hiddenimports = collect_submodules('setuptools._distutils.compilers')
- 打包时指定Hook目录:
pyinstaller --additional-hooks-dir=. your_script.py
该Hook会强制PyInstaller收集setuptools._distutils.compilers下的所有子模块,并自动处理路径结构问题。
方案2:降级setuptools到兼容版本
部分新版setuptools对_distutils的结构调整导致PyInstaller适配问题,可降级到稳定兼容版本:
pip install setuptools==68.2.2
此版本的setuptools._distutils.compilers目录包含__init__.py,能兼容PyInstaller的打包逻辑。
方案3:手动添加__init__.py(临时应急)
你已验证该方法有效,但需注意:虚拟环境更新或重新安装setuptools后,手动添加的文件会被覆盖。若使用此方法,建议在打包脚本中自动生成:
import os import sys # 获取虚拟环境site-packages路径 site_packages = next(p for p in sys.path if 'site-packages' in p) compilers_dir = os.path.join(site_packages, 'setuptools', '_distutils', 'compilers') c_dir = os.path.join(compilers_dir, 'C') # 生成空的__init__.py for dir_path in [compilers_dir, c_dir]: init_file = os.path.join(dir_path, '__init__.py') if not os.path.exists(init_file): with open(init_file, 'w') as f: pass
执行上述代码后再运行PyInstaller打包命令。
内容的提问来源于stack exchange,提问作者AK47
相关产品推荐
相关产品推荐

