You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效用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目录下的所有模块:

  1. 在项目根目录新建hooks文件夹,里面创建hook-Test.py文件,内容如下:
from PyInstaller.utils.hooks import collect_submodules

# 自动收集Test包下的所有子模块
hiddenimports = collect_submodules('Test')
  1. 修改.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 08:27:37