使用PyInstaller打包Tkinter多文件应用时遇递归深度超限错误求助
如何解决PyInstaller打包Tkinter多文件应用时的递归深度超出错误?
我用Python的Tkinter编写了一个多文件媒体应用,主文件通过subprocess将各个子文件与对应按钮关联,代码运行完全符合预期,但使用PyInstaller将应用转换为.exe文件时,出现“maximum recursion depth exceeded while calling a python object”错误,请问如何将我的.py文件成功转换为.exe?
主文件代码(main.py)
import tkinter as tk from tkinter import ttk import subprocess class PlayerExApp: def __init__(self, master): self.master = master master.title("Player Ex | Media Player") master.geometry("1280x720") # 设置初始窗口大小 self.create_widgets() def create_widgets(self): # 创建根窗口框架 root_frame = ttk.Frame(self.master, padding="10", style="White.TFrame") root_frame.pack(fill=tk.BOTH, expand=True) # 创建左侧框架 left_frame = ttk.Frame(root_frame, style="White.TFrame") left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=False, padx=(75, 75)) # 创建"Media"标题标签 heading_label = ttk.Label(left_frame, text="Media", font=("Arial", 20, "bold"), style="Black.TLabel") heading_label.pack(pady=(50, 20)) # 创建左侧按钮组 left_buttons = ttk.Frame(left_frame, style="White.TFrame") left_buttons.pack() for text, command in [("音频播放器", "audio-player.py"), ("视频播放器", "video-player.py")]: button = ttk.Button(left_buttons, text=text, style="Grey.TButton", command=lambda c=command: self.on_button_press(c)) button.pack(ipadx=90, pady=(0, 10)) # 创建"Features"标题标签 heading_label = ttk.Label(left_frame, text="功能", font=("Arial", 20, "bold"), style="Black.TLabel") heading_label.pack(pady=(50, 20)) # 创建功能按钮组 left_buttons = ttk.Frame(left_frame, style="White.TFrame") left_buttons.pack() for text, command in [("音频剪辑", "audio-clipper.py"), ("MP3转换", "video-converter.py"), ("提取人声", "root.py"), ("视频增强", "enhance-video.py")]: button = ttk.Button(left_buttons, text=text, style="Grey.TButton", command=lambda c=command: self.on_button_press(c)) button.pack(ipadx=90, pady=(0, 10)) # 创建右侧框架 right_frame = ttk.Frame(root_frame, style="Black.TFrame") right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True) # 加载并调整Logo图片 logo_img = tk.PhotoImage(file="images/logo.png") logo_img = logo_img.subsample(2) # 缩小一半 logo_label = ttk.Label(right_frame, image=logo_img) logo_label.image = logo_img logo_label.pack(side=tk.RIGHT, padx=300, expand=False) # 设置窗口响应式布局 self.master.columnconfigure(0, weight=1) root_frame.columnconfigure(0, weight=1) left_frame.columnconfigure(0, weight=1) right_frame.columnconfigure(0, weight=1) self.master.rowconfigure(0, weight=1) def on_button_press(self, command): print(f"触发命令: {command}") subprocess.run(["python", command]) def main(): root = tk.Tk() app = PlayerExApp(root) root.mainloop() if __name__ == '__main__': main()
问题根源
- 打包后的exe无法通过
subprocess.run(["python", command])找到Python环境,且子.py文件未被打包进exe,导致调用失败,进而触发递归错误(可能是错误处理逻辑或重复调用引发的循环)。 - PyInstaller单文件模式下,子进程无法直接访问原.py文件,且目标系统不一定安装Python。
解决方法
方案一:合并所有模块为单exe
将所有子文件打包进同一个exe,直接导入执行子模块,而非调用外部Python命令:
- 修改主文件的
on_button_press方法:
import sys import importlib def on_button_press(self, command): print(f"触发命令: {command}") # 移除.py后缀,导入子模块 module_name = command.replace('.py', '') # 动态导入模块 module = importlib.import_module(module_name) # 执行子模块的main函数(需确保每个子文件都有main入口) module.main()
- 确保每个子文件(如audio-player.py)都有
main()入口:
# 以audio-player.py为例 def main(): root = tk.Tk() # 子文件的原有初始化代码 root.mainloop() if __name__ == '__main__': main()
- 执行打包命令:
pyinstaller --onefile --windowed --add-data "images/*;images" main.py audio-player.py video-player.py audio-clipper.py video-converter.py root.py enhance-video.py
--onefile:生成单exe文件--windowed:隐藏命令行窗口--add-data:打包图片资源(Windows用;分隔路径,Linux/macOS用:)
方案二:多文件模式打包
保留子文件的独立结构,打包后将子文件复制到exe目录:
- 修改主文件的
on_button_press方法,用当前运行环境的解释器调用子文件:
import sys def on_button_press(self, command): print(f"触发命令: {command}") # 使用sys.executable指向当前运行的Python解释器或打包后的exe subprocess.run([sys.executable, command])
- 执行打包命令:
pyinstaller --windowed --add-data "images/*;images" main.py
- 将所有子.py文件(audio-player.py、video-player.py等)复制到生成的
dist目录下,与exe文件同级。
额外注意事项
- 递归错误也可能源于Tkinter样式的循环引用,检查自定义Style是否存在互相依赖的情况,如有需调整。
- 调试时可去掉
--windowed参数,查看命令行输出的具体错误信息。 - 确保所有资源文件(如images/logo.png)路径正确,打包后能被exe访问。
内容的提问来源于stack exchange,提问作者Defiant Softs
相关产品推荐
相关产品推荐

