PyInstaller无法排除data子目录模块,编译时仍将其打包进可执行文件
解决方案
根本原因
PyInstaller的静态依赖扫描机制会捕获代码中所有明确的import语句,你在main.py中直接写了import data.gamedata as gamedata,哪怕添加--exclude-module参数,PyInstaller依然会把gamedata.py及其导入的所有关联模块打包到可执行文件内部。程序运行时会优先加载内置的模块,所以你修改外部的.py文件不会生效。
实操步骤
1. 修改主程序导入逻辑,替换明确导入为动态导入
删除main.py中原有的import data.gamedata as gamedata语句,替换为运行时动态加载的逻辑,适配打包环境和开发环境的路径差异:
import os import sys import importlib.util from gameobj import * # 获取程序运行根目录 def get_root_path(): if getattr(sys, '_MEIPASS', False): # 打包后取exe所在目录路径 return os.path.dirname(os.path.abspath(sys.executable)) else: # 开发环境取当前脚本所在目录路径 return os.path.dirname(os.path.abspath(__file__)) root_path = get_root_path() data_path = os.path.join(root_path, "data") # 将data目录加入模块搜索路径首位,优先加载外部文件 sys.path.insert(0, data_path) # 动态加载外部的gamedata.py gamedata_spec = importlib.util.spec_from_file_location("gamedata", os.path.join(data_path, "gamedata.py")) gamedata = importlib.util.module_from_spec(gamedata_spec) sys.modules["gamedata"] = gamedata gamedata_spec.loader.exec_module(gamedata) # 后面原有测试代码无需修改 # Testing power lore_test = gamedata.lore.Lore() print(lore_test.get_desc()) # Testing effect haunt_test = gamedata.haunt.Haunt() print(haunt_test.get_desc()) # Testing spell bottomlesspit_test = gamedata.bottomlesspit.BottomlessPit() print(bottomlesspit_test.name) # testing AI dummy_ai = gamedata.dummy.Dummy() print(dummy_ai.name)
gamedata.py内部的导入逻辑无需修改,运行时会自动从外部的data目录加载对应的模块,完全支持用户自行修改新增导入内容。
2. 调整PyInstaller打包命令
移除原有针对模块的排除参数,仅保留数据目录添加规则,额外添加--exclude-module=data做保险,避免扫描到data目录的内容:
pyinstaller -n Game --exclude-module=data --add-data "res;res" --add-data "data;data" --noconfirm main.py
如果是Mac/Linux系统,需要把命令中的分号替换为冒号,即--add-data "res:res" --add-data "data:data"
3. 可选:彻底规避打包风险
如果完全不想让PyInstaller接触到data目录,打包前可以临时把data目录移出项目根目录,打包完成后再手动复制到dist/Game目录下,就完全不会出现模块被内置的问题。
验证方法
打包完成后修改dist/Game/data/ais/dummy.py中AI的名称赋值,运行exe即可看到输出已经是修改后的新名称。
内容的提问来源于stack exchange,提问作者Feldherren
相关产品推荐
相关产品推荐

