最近使用python开发了一个windows桌面应用,本篇博客就用来总结python打包的相关知识,同时简说开发。本文将记录笔者使用pyinstaller踩的所有坑。

一、环境准备(开发)

如果你已经开发完了只想打包,可以跳过此步骤。

开发一个项目通常需要使用到虚拟环境,这是为了防止在开发过程中面临环境冲突、环境污染的情况。
这里使用conda来创建虚拟环境。conda下载
conda有conda和miniconda,两者功能一样,但miniconda更小,速度更快。这里笔者使用的是miniconda。

1
2
3
4
$ conda env list  # 查看所有虚拟环境
$ conda init powershell # 初始化shell环境(windows powershell)
$ conda activate your_envs # 激活虚拟环境,your_envs为你要激活的虚拟环境名
$ conda create -n your_envs python=3.11 # 创建一个python3.11的虚拟环境

第一次使用conda来激活虚拟环境会遇到很多问题,如在初始化shell环境时会遇到:

1
2
3
4
5
6
7
. : 无法加载文件 D:\win11\Documents\WindowsPowerShell\profile.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 htt
ps:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。
所在位置 行:1 字符: 3
+ . 'D:\win11\Documents\WindowsPowerShell\profile.ps1'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : SecurityError: (:) [],PSSecurityException
+ FullyQualifiedErrorId : UnauthorizedAccess

这是 PowerShell 执行策略(Execution Policy)阻止了脚本运行,导致 conda 的初始化脚本 profile.ps1 无法加载。

✅ 解决方法(只需执行一次):

1. 打开 PowerShell(管理员模式)

  • Win + X → 选择 “Windows PowerShell(管理员)”

2. 运行以下命令,允许当前用户运行本地脚本:

1
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned

3. 按提示输入 YA 确认即可。

✅ 完成后:

关闭 PowerShell,重新打开一个 普通 PowerShell 窗口(非管理员),然后运行:

1
conda activate 你的环境名

应该就能正常使用了。

🔍 补充说明:

  • RemoteSigned 是较安全的策略,允许运行本地脚本,但远程下载的脚本需要签名。
  • 如果你不想改策略,也可以每次手动运行:
    1
    & 'D:\win11\Documents\WindowsPowerShell\profile.ps1'
    但这不是推荐方式。

虚拟环境激活后,整个项目就在这个环境中开发(这很重要,开发过程中要时刻清除你到底是用的哪个环境来开发的,环境弄错了后面可能会产生麻烦的后果)。


二、安装pyinstaller

然后是安装pyinstaller,这是python的打包工具,用来将python项目打包成exe文件。

1
2
$ conda activate your_envs  # 激活虚拟环境
$ pip install pyinstaller # 安装pyinstaller包

如果不是虚拟环境,自行省略虚拟环境的部分,包括后面的。

或者使用离线安装,安装方式:

Pyinstaller离线包链接 中选择最新版win64位的下载即可,然后安装方式同上:先激活你的虚拟环境,然后 pip install 把你刚下载好的离线文件拖到这个pip install 后面回车即可。


三、Pyinstaller 生成exe(程序无传参版)

Pyinstaller的语法在Windows,MacOS和Ubuntu的语法相同,但是在Windows下打包的应用只能在Windows下使用,MacOS和Ubuntu同理。

简易版

首先我们有一个写好的脚本test.py,然后打包指令为

1
$ pyinstaller -F test.py

会在你的python根下生成一个 builddist 文件夹还有一个 spec 文件,你生成的exe就在dist里边。双击即可运行。

进阶版

下面来看一下pyinstaller的参数

参数 说明
-h 该模块的help信息
-F 生成一个可执行文件
-D 生成一个目录(包含多个文件)作为可执行文件
-w 运行exe时,不显示命令行窗口(仅对Windows有效)
-i 该参数后跟可执行文件的icon图标路径
—distpath 该参数后跟可执行文件的路径
-n 该参数后跟可执行文件的新名字

详细参数说明请查看:PyInstaller 中文文档

笔者这次开发用的生成指令:

1
2
3
4
5
6
$ pyinstaller --onedir --contents-directory . -w ^
--add-data "resources;resources" ^
--add-data "mathjax;mathjax" ^
--hidden-import=PyQt5.sip ^
-i resources/logo.ico ^
--name Cheqory main_control.py

参数解释:
| 参数 | 说明 |
| —— | —— |
| --onedir | 生成包含所有依赖的文件夹(默认打包方式,与-D等效) |
| --contents-directory . | 输出格式保留源文件结构(Pyinstaller>=6.0.0) |
| -w | 创建Windows窗口化程序(不显示控制台,GUI模式) |
| --add-data "resources;resources" | 添加资源文件夹(格式为”源路径;目标路径”,Windows使用分号分隔) |
| --hidden-import=PyQt5.sip | 显式包含PyQt5的sip模块(自动检测可能遗漏的依赖) |
| -i logo.ico | 设置应用程序图标(需提前准备.ico格式文件) |
| --add-data "mathjax;mathjax" | 添加数学公式渲染所需的MathJax库 |
| --version-file file_version_info.txt | 注入Windows可执行文件版本信息(需单独编写版本文件) |
| --name Cheqory | 指定生成的可执行文件名称(默认与主脚本同名) |
| main_control.py | 应用程序入口文件(主程序脚本) |


四、Pyinstaller 生成exe(程序带参数版)

相信写好的脚本都有 输入输出,那么现在分两种方法进行介绍:

相对路径传参

首先在python脚本中获取当前文件路径,然后倒推同根下或者上一级文件,前提是首先把你的输入路径写死,比如

1
2
3
4
project
---- test.exe
---- input_dir
---- output_dir

那么你的python就可以通过 os.getcwd() 获取project的路径,然后向子路径寻找你的input;或者通过 os.path.dirname(os.path.abspath(__file__)) 来获取project的路径,然后告诉你的小姐姐说:你的文件都要放在这个input下才行~

然后:

1
$ pyinstaller -F test.py

指定路径传参

指定路径通过sys.argv[]来传递test.py的参数,如下

1
2
3
4
5
6
7
8
9
# test.py
import sys

def add(a, b):
c = a + b
return c

if __name__ == '__main__':
add(sys.argv[1], sys.argv[2])

在终端运行时使用 python test.py 1 2 即可。

然后:

1
$ pyinstaller -F test.py

继续:

1
2
$ cd 你的test.exe路径下
$ test.exe 1 2

这样即可通过指定参数完成传递。


五、Pyinstaller打包多个py文件为一个exe文件

打包的文件可能包含多个py脚本和一些其他类型文件,如xml, ui, pth等等。因为需要调用的文件较多, 建议将所有的非py脚本放在根目录下新建文件夹中去调用,所有的py脚本放在根目录下,这样看起来会十分的整洁,笔者亲身经历。前提要保证放在文件夹中的非py文件可以正确被调用哦。直接上栗子🌰:

你的目录长这个样子:

1
2
3
4
5
6
7
8
project
|---- test.py
|---- func1.py
|---- func2.py
|---- dir
|------ file

# test.py为你要封装的文件,func1.py和func2.py为test.py需要调用的py脚本,dir中的文件为py脚本需要调用的非py类文件

你需要这样运行即可:

1
2
3
4
5
$ cd project
$ conda activate your_env
$ pyinstaller -w -D test.py func-1.py func-2.py
# 最新测试
# pyinstaller -w -D test.py 也可以

如果想给exe添加icon,可以第三节中进阶版中的参数,是一样的。


六、踩坑和遇到的问题

  1. 程序要严谨,在程序内部使用相对路径,main主函数中的接口可以通过argv外传参数;也可以使用相对路径。建议使用第二种,简便。
  2. exe文件是可以直接拖入激活虚拟环境的cmd中进行debug的。
  3. 如果是使用虚拟环境开发,pyinstaller打包用的是虚拟环境的pyinstaller,不要随便一个目录打开终端就运行pyinstaller打包,一定要在项目目录下打开终端使用虚拟环境的pyinstaller进行打包,要不然第三方库的引用会出错。
  4. ico图标可以通过度娘 ico生成器 进行生成
  5. 被调用的脚本需要拷贝到dist中打包好的文件夹中,否则可能导致调用失败
  6. 运行exe后如果提示缺少文件,就去anaconda下搜索缺少的依赖文件,复制到exe同根下即可(其实很有可能你没成功使用开发环境的pyinstaller,要注意尤其是用了虚拟环境的)。