在Python开发中,有时需要将编写好的程序给其他人使用,尤其是打包给不懂编程的人使用,这就需要保证在不安装Python环境下能直接用,我们可以将Python程序打包成独立的可执行文件,对方点击可直接执行。PyInstaller是一个功能强大的工具,可以将Python程序打包成Windows、macOS和Linux上的可执行文件,这里就详细介绍一下PyInstaller的使用方法。

1. 安装PyInstaller

PyInstaller的安装非常简单,只需要使用pip命令即可:

pip install pyinstaller

安装完成后,可以通过以下命令验证安装是否成功:

pyinstaller --version

2. 基本使用方法

2.1 基本打包命令

PyInstaller的基本使用语法如下:

pyinstaller [选项] your_script.py

2.2 主要参数说明

参数

说明

--onefile-F

打包成单个exe文件

--onedir-D

打包成文件夹(默认)

--windowed-w

无控制台窗口(GUI程序)

--console-c

有控制台窗口(默认)

--icon=图标.ico

指定exe图标

--name=名称-n 名称

指定生成的exe名称

--add-data

添加数据文件

--hidden-import

添加隐藏导入模块

2.3 打包模式对比

2.3.1 打包成单个文件(推荐)
pyinstaller --onefile your_script.py

优点

  • 只生成一个exe文件,便于分发
  • 用户使用简单,只需双击运行

缺点

  • 启动速度相对较慢
  • 文件体积可能较大
2.3.2 打包成文件夹形式
pyinstaller your_script.py

优点

  • 启动速度快
  • 便于调试和修改

缺点

  • 生成多个文件,分发不够方便

2.4 --add-data参数详解

--add-data参数用于将程序运行时需要的文件打包到可执行文件中。

2.4.1 基本语法
pyinstaller --add-data "源路径;目标路径" your_script.py
2.4.2 实际示例

单个文件打包

pyinstaller --onefile --add-data "config.json;." main.py

文件夹打包

pyinstaller --onefile --add-data "templates;templates" main.py

多个文件打包

pyinstaller --onefile \
    --add-data "config.json;." \
    --add-data "images;images" \
    --add-data "data;data" \
    main.py
2.4.3 在程序中访问打包的文件

关键是要使用正确的路径获取方法:

import sys
import os

def get_resource_path(relative_path):
    """获取资源文件的绝对路径"""
    if hasattr(sys, '_MEIPASS'):
        # PyInstaller打包后的路径
        return os.path.join(sys._MEIPASS, relative_path)
    else:
        # 开发时的路径
        return os.path.join(os.path.abspath("."), relative_path)

# 使用示例
config_path = get_resource_path("config.json")
image_path = get_resource_path("images/logo.png")

3. 打包后的文件结构

3.1 onedir模式(文件夹形式)

dist/
└── your_app/
    ├── your_app.exe          # 主程序
    ├── config.json           # 打包的数据文件
    ├── templates/            # 打包的文件夹
    │   ├── index.html
    │   └── style.css
    ├── images/               # 打包的图片文件夹
    │   ├── logo.png
    │   └── icon.gif
    └── _internal/            # Python运行时和库
        ├── pandas/
        ├── numpy/
        └── 其他库...

3.2 onefile模式(单文件形式)

dist/
└── your_app.exe             # 单个文件,包含所有内容

当运行时,PyInstaller会:

  1. 在临时目录中解压所有文件
  2. 文件结构与onedir模式相同
  3. 程序运行结束后清理临时文件

3.3 依赖库的处理

PyInstaller会自动分析并打包程序所依赖的所有第三方库:

  • 自动检测导入的模块
  • 递归包含所有依赖
  • 包含Python解释器

例如,如果你的程序使用了pandas、numpy、matplotlib等库,PyInstaller会自动将这些库打包进去。

3.4 主程序以外文件的处理

对于配置文件、图片、模板等非Python文件:

  • 需要使用--add-data参数显式指定
  • 打包到程序内部的特定位置
  • 运行时通过特殊路径访问

3.5 PyInstaller打包后目录文件说明

3.5.1 build/ 目录

是临时文件,打包完成后通常可以安全删除:

(1)可以删除的情况

  • ✅ 你已经成功生成了dist目录中的文件
  • ✅ 不需要重新打包或调试构建过程
  • ✅ 满意当前的打包结果

(2)建议保留的情况

  • 🔧 需要频繁重新打包(保留可加快构建速度)
  • 🔍 需要调试构建问题
  • 📊 需要查看警告信息(warn-*.txt文件)
3.5.2 dist/ 目录

不是临时文件,是最终产物:

必须保留

  • ✅ 这是你要分发给用户的文件
  • ✅ 删除后需要重新打包才能获得
  • ✅ 可以直接运行和分发

4. 为可执行文件添加图标

4.1 准备图标文件

图标必须是.ico格式,建议包含多种尺寸(16x16, 32x32, 48x48, 256x256)。

制作ICO图标的方法:

方法1:在线转换工具

  • convertio.co
  • online-convert.com
  • icoconvert.com

方法2:使用Python制作

from PIL import Image
img = Image.open('icon.png')
img.save('icon.ico', format='ICO')

4.2 添加图标

命令行方式

pyinstaller --onefile --icon=icon.ico your_script.py

完整示例

pyinstaller --onefile \
    --windowed \
    --icon=resources/app_icon.ico \
    --add-data "resources/logo.gif;." \
    --name="我的应用程序" \
    main.py

5. spec文件详解

5.1 什么是spec文件

spec文件是PyInstaller的配置文件,用于进行更精细的打包控制。当你第一次运行PyInstaller时,会自动生成一个同名的.spec文件。

5.2 生成和使用spec文件

# 首次运行生成spec文件
pyinstaller your_script.py

# 编辑spec文件后使用
pyinstaller your_script.spec

5.3 spec文件结构示例

# your_script.spec
a = Analysis(
    ['your_script.py'],
    datas=[
        ('config.json', '.'),
        ('templates', 'templates'),
        ('images/*.png', 'images'),
    ],
    hiddenimports=[
        'hidden_module1',
        'hidden_module2',
    ],
)

exe = EXE(
    pyz,
    a.scripts,
    a.binaries,
    a.zipfiles,
    a.datas,
    [],
    name='YourApp',
    icon='app.ico',
    console=False,
)

5.4 自定义配置的优势

  1. 精细控制:可以精确控制包含的文件和模块
  2. 复杂配置:支持多个可执行文件、特殊运行时配置
  3. 版本控制:配置文件可以纳入版本控制
  4. 团队协作:统一的打包配置,确保一致性

6. Python GUI框架对比

PyInstaller对不同的GUI框架都有很好的支持,主要包括tkinter和Qt。

6.1 tkinter和Qt对比

特性

tkinter

PyQt/PySide

内置性

Python标准库,无需额外安装

需要单独安装第三方库

学习难度

简单易学,适合初学者

功能强大但学习曲线较陡

界面美观度

界面相对简单,原生风格

界面美观,可定制性强

功能丰富度

基本功能,相对简单

功能丰富,组件多样

性能

轻量级,性能较好

功能丰富但相对较重

跨平台

良好支持

优秀支持

文档资源

官方文档,中文资源多

官方文档,英文资源多

社区支持

Python官方支持

活跃社区,商业支持

6.2 打包示例

6.2.1 tkinter程序打包
# tkinter_app.py
import tkinter as tk
from tkinter import messagebox

def show_message():
    messagebox.showinfo("信息", "Hello World!")

root = tk.Tk()
root.title("tkinter应用")
button = tk.Button(root, text="点击我", command=show_message)
button.pack()
root.mainloop()

打包命令:

pyinstaller --onefile --windowed tkinter_app.py
6.2.2 PyQt程序打包
# pyqt_app.py
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("PyQt应用")
        button = QPushButton("点击我", self)
        button.clicked.connect(self.show_message)
        
    def show_message(self):
        QMessageBox.information(self, "信息", "Hello World!")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

打包命令:

pyinstaller --onefile --windowed pyqt_app.py

6.2.3 示例

以下是用tkinter写的一个简单程序,执行后可生成爱心和hello world字样。

import tkinter as tk
import math
import threading
import time


class HeartAnimation:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("Heart Animation")
        self.root.geometry("800x600")
        self.root.configure(bg='white')

        # 创建画布
        self.canvas = tk.Canvas(self.root, width=800, height=600, bg='white', highlightthickness=0)
        self.canvas.pack(fill=tk.BOTH, expand=True)

        # 动画参数
        self.points = []
        self.rendered_points = []
        self.animation_running = False

        # 生成爱心形状的点
        self.generate_heart_points()

    def heart_parametric(self, t):
        """
        爱心的参数方程
        x = 16sin³(t)
        y = 13cos(t) - 5cos(2t) - 2cos(3t) - cos(4t)
        """
        x = 16 * math.sin(t) ** 3
        y = 13 * math.cos(t) - 5 * math.cos(2 * t) - 2 * math.cos(3 * t) - math.cos(4 * t)
        return x, y

    def generate_heart_points(self):
        """
        生成爱心形状的所有点
        """
        self.points = []
        # 生成爱心轮廓上的点
        for i in range(100):
            t = i * 2 * math.pi / 100
            x, y = self.heart_parametric(t)
            # 调整坐标和大小以适应画布
            x = x * 10 + 400
            y = -y * 10 + 300  # y轴翻转使爱心正向
            self.points.append((x, y))

    def animate_heart(self):
        """
        动画函数,逐个显示红点形成爱心
        """
        self.animation_running = True
        total_points = len(self.points)
        animation_duration = 1.5  # 1.5秒内完成动画
        interval = animation_duration / total_points

        # 逐个显示点
        for i, point in enumerate(self.points):
            self.rendered_points.append(point)
            # 在主线程中更新UI
            self.root.after(0, self.draw_point, point)
            time.sleep(interval)

        # 动画完成后显示文字
        self.root.after(0, self.show_text)
        self.animation_running = False

    def draw_point(self, point):
        """
        在画布上绘制一个红色点
        """
        x, y = point
        # 绘制小圆点 (半径为2)
        self.canvas.create_oval(x - 2, y - 2, x + 2, y + 2, fill='red', outline='red', tags="heart_point")

    def show_text(self):
        """
        显示"hello world"文字
        """
        self.canvas.create_text(400, 300, text="hello world", fill="orange", font=("Arial", 24, "bold"))

    def start_animation(self):
        """
        启动动画线程
        """
        animation_thread = threading.Thread(target=self.animate_heart)
        animation_thread.daemon = True
        animation_thread.start()

    def run(self):
        """
        运行主程序
        """
        # 窗口居中显示
        self.root.update_idletasks()
        x = (self.root.winfo_screenwidth() // 2) - (800 // 2)
        y = (self.root.winfo_screenheight() // 2) - (600 // 2)
        self.root.geometry(f"800x600+{x}+{y}")

        # 启动动画
        self.start_animation()

        # 启动GUI主循环
        self.root.mainloop()


if __name__ == "__main__":
    app = HeartAnimation()
    app.run()

7. 总结

PyInstaller是一个功能强大且易于使用的Python打包工具。通过本文的介绍,你应该掌握了:

  1. 基础安装和使用:简单的pip安装和基本命令
  2. 参数配置:各种打包选项的使用方法
  3. 文件处理:如何包含数据文件和资源文件
  4. 图标设置:为可执行文件添加自定义图标
  5. 高级配置:使用spec文件进行精细控制
  6. GUI支持:对不同GUI框架的支持

在实际使用中,建议:

  • 简单项目使用命令行参数快速打包
  • 复杂项目使用spec文件进行精细控制
  • 打包后务必测试程序运行效果
  • 注意文件路径的正确处理

Logo

电影级数字人,免显卡端渲染SDK,十行代码即可调用,工业级demo免费开源下载!

更多推荐