如何高效用PyInstaller打包含importlib动态导入的Python3.9.10项目?
问题描述
代码结构如下:
main.py .\Main_dependency |__ test_calling_script.py .\Test |__ test1.py |__ test2.py : |__ testN.py
使用importlib动态导入模块的代码:
test_module = getattr(import_module(f'Test.{prm.TestFile}'), prm.TestName)
其中prm.TestName是test<n>.py中的函数名。
代码在终端/IDE运行正常,用PyInstaller打包成.exe后,目前需要在.spec文件的hiddenimports中逐个添加动态导入的文件路径,但随着文件增多,.spec会变得混乱。尝试将Test目录添加到.spec的pathex中,依然出现NoModuleFoundError,无法替代hiddenimports的作用,求更高效简洁的实现方式。
解决方法
方法1:自动生成hiddenimports列表
直接在.spec文件中写代码遍历Test目录,自动生成需要导入的模块列表,不用手动维护:
import os # 遍历Test目录下的所有py文件,生成模块名列表 test_dir = './Test' hidden_imports = [] for filename in os.listdir(test_dir): if filename.endswith('.py') and not filename.startswith('__'): # 转换为模块格式,比如test1.py → Test.test1 module_name = f'Test.{filename[:-3]}' hidden_imports.append(module_name) a = Analysis( ['main.py'], pathex=['./'], binaries=[], datas=[], hiddenimports=hidden_imports, # 用自动生成的列表替换手动输入 hookspath=[], hooksconfig={}, runtime_hooks=[], excludes=[], noarchive=False, ) # 后续的pyz、exe等配置保持不变
以后新增testN.py,打包时会自动被加入hiddenimports,不用手动修改.spec。
方法2:用自定义hook文件让PyInstaller自动识别
创建PyInstaller的hook文件,自动收集Test目录下的所有模块:
- 在项目根目录新建
hooks文件夹,里面创建hook-Test.py文件,内容如下:
from PyInstaller.utils.hooks import collect_submodules # 自动收集Test包下的所有子模块 hiddenimports = collect_submodules('Test')
- 修改
.spec文件的hookspath参数,指向这个hooks目录:
a = Analysis( ['main.py'], pathex=['./'], binaries=[], datas=[], hiddenimports=[], hookspath=['./hooks'], # 指定hook文件所在目录 hooksconfig={}, runtime_hooks=[], excludes=[], noarchive=False, )
PyInstaller打包时会读取这个hook文件,自动把Test下的所有模块加入打包列表。
方法3:在代码中显式触发导入(适合可枚举模块的场景)
如果prm.TestFile的可选值是固定范围的,或者可以遍历获取,可以在代码中加一段仅打包时执行的导入逻辑,让PyInstaller检测到这些模块:
# 可以放在main.py或者test_calling_script.py里 import sys import os import importlib if getattr(sys, 'frozen', False): # 仅当打包成exe时执行这段代码 test_dir = os.path.join(os.path.dirname(__file__), 'Test') for filename in os.listdir(test_dir): if filename.endswith('.py') and not filename.startswith('__'): module_name = f'Test.{filename[:-3]}' importlib.import_module(module_name)
这种方式不需要修改.spec文件,PyInstaller扫描代码时会捕捉到这些导入,自动打包对应的模块。
内容的提问来源于stack exchange,提问作者pedru
相关产品推荐
相关产品推荐

