前言
虽然很多开发者专注于 Web 开发,但对 Python 的众多开源项目一直都很关注。像 Stable Diffusion 的 AI 绘画,以及 So-VITS-SVC 音色替换等项目的源码部署文档通常比较完善。尽管如此,对于刚入门或本地环境搭建容易踩坑的同学来说,直接运行源码往往不太友好。针对这一现象,网上已有各种解决方案提供一键部署,无需安装 Python 环境,无需下载各种依赖包,点击 exe 即可使用。
那么这些方案是如何实现的呢?很多人会想到 PyInstaller。它确实可以解决整体环境的打包问题,但有时候一些图标和依赖文件需要放在一起才能正常使用,类似于绿色桌面工具。有没有方法对这个进一步封装,就是点击 exe 后需要安装,然后安装后才是项目的文件,还可以卸载?答案是使用 Inno Setup Compiler。接下来我将用一个 GUI 的小 demo 完成 exe 打包和进一步安装打包。

环境准备
为了确保打包过程顺利,建议准备以下环境:
- Python 3.8 及以上版本
- Tkinter (Python 自带 GUI 库)
- PyInstaller 6.3.0 或更高版本
- Inno Setup Compiler (用于制作安装包)
建议使用 Conda 创建独立的虚拟环境,避免系统全局环境冲突。
基本流程
- 环境创建:用 conda 单独创建一个虚拟环境,例如
tools_env。 - 编写代码:编写一个 tkinter 应用,为了美观,准备尺寸 32x32 和 64x64 的图标文件。
- PyInstaller 打包:将应用打成文件包(含 exe),生成 dist 目录。
- Inno Setup 打包:使用 Inno Setup Compiler 对 dist 目录进行打包,设置文件关联、图标和信息,最终生成带有安装向导和卸载功能的安装包。

开始操作
1. 环境创建
# 1. 创建环境
conda create -n tools_env python=3.8
# 2. 进入环境
conda activate tools_env
# 3. 安装 pyinstaller
pip install pyinstaller -i https://pypi.tuna.tsinghua.edu.cn/simple
2. 编码示例
以下是一个简单的批量重命名工具示例,使用了 Tkinter 构建界面。注意清理了原有的推广信息。
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
import os
class Application(tk.Tk):
def __init__(self):
super().__init__()
self.title("文件批量重命名工具")
# 确保 iconbitmap 路径正确,打包时需放入同一目录
try:
self.iconbitmap('logo.ico')
except:
pass
self.geometry("600x370") # 设置固定的窗口大小
self.resizable(False, False) # 禁止调整窗口大小
self.style = ttk.Style(self)
self.main_color = self.cget("bg")
self.style.configure("TEntry",
padding=6,
relief="flat",
background="#0078d7",
foreground="black",
font=("Arial", 12, "bold"))
self.style.configure("TLabel",
font=("Arial", 12, "bold"))
self.style.configure("TButton",
padding=6,
font=("Arial", 12))
self.create_widgets()
def create_widgets(self):
self.path_label = ttk.Label(self, text='绝对路径:')
self.path_label.grid(row=0, sticky=tk.W, pady=30, padx=20)
self.path = tk.StringVar()
self.path_entry = ttk.Entry(self, width=60, textvariable=self.path)
self.path_entry.grid(row=0, column=1, sticky=tk.E, pady=5)
self.rename_label = ttk.Label(self, text='修改名称:')
self.rename_label.grid(row=1, sticky=tk.W, pady=5, padx=20)
self.rename = tk.StringVar()
self.rename_entry = ttk.Entry(self, width=60, textvariable=self.rename)
self.rename_entry.grid(row=1, column=1, sticky=tk.E, pady=5)
self.msg_text = tk.Text(self, height=2, width=60, wrap='none')
self.msg_text.grid(row=2, column=1, sticky=tk.W, pady=15)
self.msg_text.configure(bd=0, relief="solid", bg=self.main_color)
ttk.Button(self, text='确认修改', command=self.start_program).grid(row=3, column=1, sticky=tk.W, pady=20, padx=120)
ttk.Button(self, text='关于', command=self.about).grid(row=4, column=1, sticky=tk.W, padx=120)
def start_program(self):
path = self.path.get()
rename = self.rename.get()
if path == "" or rename == "":
messagebox.showwarning("警告", "输入框不能为空!")
return
if not os.path.isdir(path):
messagebox.showwarning("警告", "绝对路径不正确!")
return
i = 0
FileList = os.listdir(path)
for files in FileList:
oldDirPath = os.path.join(path, files)
self.msg_text.delete(1.0, tk.END)
self.msg_text.insert(tk.END, f"处理中:{oldDirPath}")
if os.path.isdir(oldDirPath):
continue # 简化逻辑,仅处理文件
fileName = os.path.splitext(files)[0]
fileType = os.path.splitext(files)[1].lower()
newDirPath = os.path.join(path, f"{rename}_{i}{fileType}")
try:
os.rename(oldDirPath, newDirPath)
i += 1
except Exception as e:
print(f"重命名失败:{files}, 错误:{e}")
messagebox.showinfo("信息", "操作完成!")
def about(self):
messagebox.showinfo("关于", "工具:批量修改文件 1.0\n作者:技术团队")
def quit_program(self):
self.destroy()
if __name__ == "__main__":
app = Application()
app.mainloop()
3. 开始打包
使用 PyInstaller 将脚本转换为可执行文件。命令如下:
pyinstaller -F -w Application.py --icon=logo.ico
参数说明:
--icon=图标路径:指定 exe 图标。-F:打包成一个 exe 文件。-w:使用窗口模式,无控制台黑框。-c:使用控制台模式,有黑框。-D:创建一个目录,里面包含 exe 以及其他一些依赖性文件。
如果修改了代码需要重新打包,建议删除上一次生成的 .spec 后缀文件,以免配置冲突。打包成功后,控制台会显示 Building EXE from EXE-00.toc completed successfully。根目录下的 dist 文件夹即为打包后的文件包,里面包含了 exe 及所需的动态链接库和图片等资源。


4. Inno Setup Compiler 操作
Inno Setup 是一款免费且强大的 Windows 安装程序制作软件。我们需要编写一个脚本文件(.iss)来定义安装过程。
新建脚本
打开 Inno Setup Compiler,选择新建脚本向导,填写应用程序名称、版本号等信息。

选择主程序和文件
在文件选择步骤中,指向之前 PyInstaller 生成的 dist 文件夹中的 exe 文件,并勾选其他需要的资源文件。

设置名称和图标
设置安装程序的标题、公司名称以及安装图标。

导出位置
选择编译后的安装包输出路径。在生成前还可以设置协议条款等高级选项。

运行脚本
点击运行按钮开始生成安装包。

安装效果
安装完成后,安装目录内会自带卸载程序,用户可以在'控制面板'或'设置'中轻松卸载。

深入:Inno Setup 脚本详解
为了更灵活地控制安装过程,我们可以手动编辑 .iss 脚本文件。以下是标准脚本结构的详细说明:
[Setup]
AppName=My Program
AppVersion=1.0
DefaultDirName={autopf}\MyProgram
DefaultGroupName=My Program
OutputDir=output
OutputBaseFilename=setup
Compression=lzma
SolidCompression=yes
WizardStyle=modern
[Files]
Source: "dist\*.exe"; DestDir: "{app}"
Source: "dist\*.dll"; DestDir: "{app}"
Source: "images\*.*"; DestDir: "{app}\images"
[Icons]
Name: "{group}\{cm:UninstallProgram,MyProgram}"; Filename: "{uninstallexe}"
Name: "{autodesktop}\MyProgram"; Filename: "{app}\myprogram.exe"
[Run]
Filename: "{app}\myprogram.exe"; Description: "{cm:LaunchProgram,MyProgram}"; Flags: nowait postinstall skipifsilent
- [Setup]:定义安装程序的基本属性,如应用名、版本、默认安装目录
{app}代表用户选择的目录,{autopf}代表 Program Files。 - [Files]:指定要复制的文件。
Source是源路径,DestDir是目标路径。支持通配符。 - [Icons]:创建快捷方式。
{group}代表开始菜单组,{autodesktop}代表桌面。 - [Run]:安装完成后自动运行的程序。
nowait表示不等待程序结束,postinstall表示在安装结束时运行。
常见问题与解决方案
1. 缺少 DLL 报错
如果在运行 exe 时提示缺少 MSVCP140.dll 等文件,说明缺少 Visual C++ 运行库。解决方法是在 PyInstaller 打包时添加 --add-data 参数引入必要的 DLL,或者在 Inno Setup 脚本中添加 VC++ 运行库的安装逻辑。
2. 杀毒软件误报
由于未签名的 exe 容易被杀毒软件拦截。建议申请代码签名证书(Authenticode)对 exe 进行签名,或者在发布前告知用户添加信任白名单。
3. 打包体积过大
PyInstaller 默认会将所有依赖打包进去。可以使用 --onefile 优化,或者检查是否有不必要的模块被引入。对于大型项目,考虑使用 --onedir 模式,体积会更小且加载更快。
4. 中文乱码
确保源代码文件保存为 UTF-8 格式。在 PyInstaller 打包时,如果遇到中文路径问题,可以尝试在脚本开头添加 # -*- coding: utf-8 -*-。
总结
通过结合 PyInstaller 和 Inno Setup Compiler,开发者可以将 Python 项目转化为专业的 Windows 应用程序。这不仅解决了环境依赖问题,还提升了用户体验。掌握上述流程后,您可以轻松分发自己的工具软件,无需用户具备编程背景即可使用。

