Python 生成可执行文件附录#

将 Python 脚本打包为独立可执行文件,可在无 Python 环境的机器上运行,便于分发与部署。

核心概念#

为何需要可执行文件#

  • 无 Python 环境:目标机器未安装 Python 或版本不一致时仍可运行。
  • 便于分发:单文件或单目录即可交付,无需配置依赖。
  • 保护源码:打包后用户难以直接查看或修改源码(非强加密)。

实现方式概览#

方式代表工具原理
打包器PyInstaller、cx_Freeze将解释器、依赖与脚本打包成目录或单文件,运行时解压/加载。
编译型Nuitka将 Python 编译为 C,再编译为原生二进制,无内置解释器。

工具选型简表#

工具适用场景跨平台依赖复杂度体积/启动
PyInstaller通用、快速打包低,自动分析多单文件较大、首次略慢
cx_Freeze需精细控制、跨平台一致中,常需写配置目录分发,可控
Nuitka追求性能、体积或兼容性高,需 C 编译器体积与启动更优,编译慢

PyInstaller(推荐首选)#

安装#

pip install pyinstaller

单文件与目录打包#

  • 单文件:产出单个 exe(Windows)或可执行文件,运行时解压到临时目录。适合分发。
  • 目录:产出一个目录,内含可执行文件与依赖。启动更快,便于调试。
# 单文件(最常用)
pyinstaller --onefile script.py

# 目录模式(默认)
pyinstaller script.py

常用参数#

参数说明
--onefile / -F打包成单文件
--name / -n指定生成的可执行文件名
--icon / -i指定图标(Windows .ico)
--add-data将数据文件/目录打进包(格式:src;destsrc:dest
--hidden-import显式加入未自动检测到的模块
--console / --noconsole是否保留控制台(GUI 程序常用 --noconsole

示例:

pyinstaller --onefile --name myapp --icon app.ico \
    --add-data "config.json;." \
    --hidden-import pandas \
    script.py

打包后访问资源路径#

单文件运行时,脚本所在目录是临时解压目录,需用 sys._MEIPASS 定位资源:

import sys
import os

def resource_path(relative_path):
    """获取打包后资源文件的绝对路径。"""
    if hasattr(sys, '_MEIPASS'):
        return os.path.join(sys._MEIPASS, relative_path)
    return os.path.join(os.path.abspath('.'), relative_path)

config_path = resource_path('config.json')

spec 文件#

spec 是 PyInstaller 的构建规格文件(Python 脚本),用于精确控制打包内容与流程,便于版本管理、复现构建。

生成与使用

  • 首次执行 pyinstaller script.py 会在当前目录生成 script.spec
  • 之后用 pyinstaller script.spec 构建,命令行参数以 spec 为准;修改 spec 即可调整打包结果,无需长命令。

主要可配置项

区块说明
Analysis入口脚本、依赖、pathexhiddenimportsdatas(数据文件)、excludes 等。
PYZ打包进 PYZ 的模块(通常自动)。
EXE单文件可执行:a(Analysis 实例)、consoleiconname 等。
COLLECT目录模式:收集 exe、依赖、数据到输出目录(单文件模式无此块)。

示例(单文件)

# script.spec 精简示例
# 执行: pyinstaller script.spec

a = Analysis(
    ['script.py'],
    pathex=[],
    binaries=[],
    datas=[('config.json', '.')],
    hiddenimports=['pandas'],
    excludes=['tkinter'],
)

pyz = PYZ(a.pure)

exe = EXE(
    pyz,
    a.scripts,
    a.binaries,
    a.datas,
    name='myapp',
    console=False,
    icon='app.ico',
)

何时用 spec

  • 需要稳定、可复现的构建(CI 或团队协作)。
  • 依赖、数据文件、排除项较多,命令行难以维护。
  • 多入口或需在构建前后执行自定义逻辑(spec 中可写 Python 代码)。

cx_Freeze#

安装与基本用法#

pip install cx_Freeze

命令行快速打包:

# 将 script.py 打包为可执行文件(默认生成目录)
cxfreeze script.py --target-dir dist

使用 setup.py 配置(推荐)#

便于控制依赖、多脚本与数据文件:

from cx_Freeze import setup, Executable

build_exe_options = {
    'packages': ['numpy', 'pandas'],
    'excludes': ['tkinter'],
    'include_files': ['config.json'],
}

setup(
    name='myapp',
    version='1.0',
    description='My Application',
    options={'build_exe': build_exe_options},
    executables=[Executable('script.py', target_name='myapp')],
)

然后执行:

python setup.py build

与 PyInstaller 对比#

  • 配置:cx_Freeze 常用 setup.py 或配置文件,适合项目化、多入口;PyInstaller 命令行即可完成大部分场景。
  • 适用:需严格控制包含/排除模块、或与 setuptools 集成时,cx_Freeze 更灵活;日常单脚本分发优先 PyInstaller。

Nuitka#

特点#

  • 将 Python 编译为 C,再编译为原生二进制,无内置解释器。
  • 运行性能与启动速度通常优于打包器方案;体积可能更小。
  • 编译需 C 编译器(如 Windows 上的 MinGW64/MSVC),编译时间较长。

基本命令#

pip install nuitka

# 基本编译(生成可执行文件)
nuitka script.py

# 单文件模式(需 onefile 插件)
nuitka --onefile script.py

# 指定输出名
nuitka --output-filename=myapp script.py

使用注意#

  • 首次使用需安装 C 编译器,Windows 上 Nuitka 会提示下载依赖。
  • 部分动态特性(如大量 eval、复杂反射)可能受限。
  • 适合对性能、体积或兼容性有明确需求的场景,一般分发可优先 PyInstaller。

常见问题与细节#

杀毒软件误报#

  • 打包器生成的 exe 常被误报为病毒(行为类似自解压、内存加载)。
  • 应对:代码签名(Windows 需证书)、上传厂商白名单、或改用目录分发 + 说明用户添加信任。

体积过大#

  • 原因:打包了完整解释器与依赖(如 numpy、PyQt)。
  • 应对:用虚拟环境只装必要依赖;--exclude-module 排除不需要的库;考虑 Nuitka 或 UPX 压缩(注意部分环境对 UPX 敏感)。

缺失依赖(ImportError / ModuleNotFoundError)#

  • 动态导入或插件式加载的模块可能未被自动分析到。
  • 应对:PyInstaller 用 --hidden-import;cx_Freeze 在 packages/includes 中显式加入;Nuitka 用 --include-module

路径与 sys._MEIPASS#

  • 单文件运行时,当前工作目录可能是用户启动目录,而资源在临时目录。
  • 始终用 sys._MEIPASS(或封装好的 resource_path)定位打包进去的数据文件,避免写死相对路径。

多平台注意#

  • Windows:产出 .exe;GUI 程序可用 --noconsole 隐藏控制台。
  • Linux / macOS:产出无扩展名或平台约定名称的可执行文件;注意动态库与权限。
  • 各平台需在对应系统下分别打包,无法在一个平台上直接生成另一平台的可执行文件。

参考链接#