cx_Freeze 是一个非常流行和强大的打包工具,它可以将你的 Python 脚本及其所有依赖项(包括库、数据文件等)捆绑到一个或多个文件中,从而在没有安装 Python 环境的 Windows 机器上运行。

目录
- 准备工作
- 基本打包步骤
- 处理依赖项(关键步骤)
- 包含数据文件(如图片、配置等)
- 打包选项详解
- 完整示例:一个带 GUI 和数据文件的程序
- 常见问题与解决方案
准备工作
你需要确保你的 Python 环境已经安装了 cx_Freeze。
安装 cx_Freeze
打开你的命令行工具(如 cmd 或 PowerShell),然后运行:
pip install cx_Freeze
准备一个简单的 Python 脚本

为了演示,我们创建一个名为 hello.py 的简单脚本。
# hello.py
import sys
import time
def main():
print("Hello from a frozen executable!")
print("Python version:", sys.version)
for i in range(5):
print(f"Counting: {i}")
time.sleep(1)
print("Program finished.")
if __name__ == "__main__":
main()
基本打包步骤
cx_Freeze 的核心是一个名为 setup.py 的构建脚本,你需要在你的项目根目录下创建这个文件。
创建 setup.py
在 hello.py 同一个目录下,创建 setup.py 文件:

# setup.py
from cx_Freeze import setup, Executable
# 基本设置
setup(
name="MyHelloApp",
version="0.1",
description="My first frozen application",
executables=[Executable("hello.py")]
)
执行打包命令
打开命令行,切换到 setup.py 和 hello.py 所在的目录,然后运行:
python setup.py build
执行成功后,你会看到一个新的 build 目录,进入 build 目录,再进入 exe.win-amd64-3.10(或类似名称,取决于你的 Python 版本和系统架构)子目录,你就能找到 hello.exe 文件。
你可以直接运行它,或者将其复制到任何一台 Windows 电脑上运行,无需安装 Python。
处理依赖项(关键步骤)
对于简单的脚本,cx_Freeze 通常能自动找到所有依赖项,但对于复杂的项目,特别是使用了第三方库(如 requests, numpy, Pillow 等)时,自动检测可能会失败。
手动指定依赖项
为了确保所有库都被正确包含,最佳实践是在 setup() 函数中使用 options 参数来指定。
# setup.py
from cx_Freeze import setup, Executable
# 定义可执行文件
executables = [
Executable("hello.py")
]
# 设置打包选项
build_exe_options = {
# "packages": ["os", "sys", "time"], # 可以手动指定要包含的包
"includes": [ # 更推荐使用 includes,显式包含可能被遗漏的模块
"tkinter", # 如果使用 Tkinter GUI,必须包含
"PIL", # 如果使用 Pillow (PIL),必须包含
"requests", # 如果使用 requests,必须包含
"numpy" # 如果使用 numpy,必须包含
],
"excludes": [ # 排除不需要的包,可以减小体积
"matplotlib", # 如果你没用它,可以排除
"unittest"
],
"include_files": [ # 包含数据文件,见下一节
# ("source_path", "dest_path_in_exe")
]
}
setup(
name="MyHelloApp",
version="0.1",
description="My first frozen application",
options={"build_exe": build_exe_options},
executables=executables
)
如何找到需要包含的模块?
如果打包后的程序运行时提示 ModuleNotFoundError,你就需要找出是哪个模块没有被包含。
- 查看错误信息:错误信息会告诉你缺少哪个模块,
No module named 'requests'。 - 手动添加:将缺少的模块名添加到
build_exe_options的includes列表中。 - 重复打包和测试:修改
setup.py后,重新运行python setup.py build并测试。
包含数据文件(如图片、配置等)
如果你的程序需要额外的文件,比如图片、配置文件、数据库等,你需要告诉 cx_Freeze 将它们复制到最终生成的可执行文件旁边。
使用 include_files 选项。
假设你的项目结构如下:
my_project/
├── hello.py
├── setup.py
└── assets/
├── icon.png
└── config.json
修改 setup.py
# setup.py
from cx_Freeze import setup, Executable
import os
# 定义可执行文件
executables = [
Executable(
"hello.py",
base="Win32GUI" if sys.platform == "win32" else None,
icon="assets/icon.ico" # 可选:指定图标
)
]
# 数据文件路径
# os.path.join 用于跨平台路径拼接
data_files = [
(os.path.join("assets", "images"), ["assets/icon.png"]), # 将 icon.png 复制到 exe 旁边的 assets/images 目录
(os.path.join("assets"), ["assets/config.json"]) # 将 config.json 复制到 exe 旁边的 assets 目录
]
# 设置打包选项
build_exe_options = {
"include_files": data_files,
"includes": ["json"] # config.json 是 json 格式,确保包含 json 模块
}
setup(
name="MyHelloApp",
version="0.1",
description="My first frozen application",
options={"build_exe": build_exe_options},
executables=executables
)
打包后,在 build/exe.win-amd64-3.10 目录下,你会看到 assets 文件夹,里面包含了 icon.png 和 config.json。
在代码中访问数据文件
在 hello.py 中,你需要使用特殊变量 sys._MEIPASS 来获取可执行文件所在的临时目录,然后拼接路径。
# hello.py
import sys
import os
import json
def get_resource_path(relative_path):
"""获取资源的绝对路径,无论是开发环境还是打包后"""
try:
# PyInstaller 创建的临时文件夹
base_path = sys._MEIPASS
except Exception:
# 开发环境
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
def main():
# 打印欢迎信息
print("Hello from a frozen executable!")
# 读取配置文件
config_path = get_resource_path(os.path.join("assets", "config.json"))
if os.path.exists(config_path):
with open(config_path, 'r') as f:
config = json.load(f)
print("Config loaded:", config)
else:
print("Config file not found!")
# 读取图片路径(仅作示例,不能直接在exe中用open读取图片)
# icon_path = get_resource_path(os.path.join("assets", "icon.png"))
# print(f"Icon path: {icon_path}")
if __name__ == "__main__":
main()
打包选项详解
setup() 和 Executable() 函数有很多有用的参数:
-
Executable(script, ...):script: 要打包的主脚本路径。base: 可执行文件的基类。None: 控制台程序(黑窗口)。Win32GUI: Windows GUI 程序(无黑窗口),打包 GUI 程序(如 Tkinter, PyQt)时必须使用。Console: 显式指定为控制台程序。
icon:.ico图标文件的路径。targetName: 生成的.exe文件名。compress: 是否压缩。True可以减小体积,但可能略微增加启动时间。
-
setup(..., options={"build_exe": ...}):packages: 自动包含指定包及其所有子包。includes: 显式包含模块(推荐用于解决依赖问题)。excludes: 排除模块,减小体积。include_files: 包含数据文件,如上所述。binaries: 包含非 Python 的二进制依赖(如某些 DLL 文件),很少需要手动设置。path: 指定 Python 模块的搜索路径。optimize: 优化级别,如2。
完整示例:一个带 GUI 和数据文件的程序
项目结构
my_app/
├── app.py # 主程序
├── setup.py # 打包脚本
├── assets/
│ ├── icon.ico # 程序图标
│ └── style.css # 样式文件
└── requirements.txt # 依赖列表
requirements.txt
tkinter
Pillow
app.py (使用 Tkinter)
# app.py
import tkinter as tk
from tkinter import messagebox
import sys
import os
def get_resource_path(relative_path):
"""获取资源的绝对路径"""
try:
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
def show_message():
messagebox.showinfo("Hello", "This is a message from a frozen app!")
def main():
root = tk.Tk()
root.title("My Frozen App")
# 设置图标
icon_path = get_resource_path("assets/icon.ico")
if os.path.exists(icon_path):
root.iconbitmap(icon_path)
# 读取并应用样式(仅作示例,Tkinter 内置样式)
# style_path = get_resource_path("assets/style.css")
# if os.path.exists(style_path):
# with open(style_path, 'r') as f:
# # 这里需要额外的库来应用CSS,ttkstyle
# pass
label = tk.Label(root, text="Welcome to my frozen application!", font=("Arial", 14))
label.pack(pady=20)
button = tk.Button(root, text="Click Me!", command=show_message)
button.pack(pady=10)
root.mainloop()
if __name__ == "__main__":
main()
setup.py
# setup.py
import sys
from cx_Freeze import setup, Executable
# 如果是控制台程序,base=None;如果是GUI程序,base="Win32GUI"
# Tkinter 是 GUI 框架,所以使用 Win32GUI
base = "Win32GUI" if sys.platform == "win32" else None
# 数据文件
data_files = [
(os.path.join("assets"), ["assets/icon.ico"])
]
build_exe_options = {
"include_files": data_files,
"includes": ["tkinter"], # 显式包含 tkinter
}
setup(
name="MyTkinterApp",
version="1.0",
description="A simple Tkinter application frozen with cx_Freeze",
options={"build_exe": build_exe_options},
executables=[
Executable(
"app.py",
base=base,
icon="assets/icon.ico",
target_name="MyApp.exe"
)
]
)
打包和运行
- 安装依赖:
pip install -r requirements.txt - 打包:
python setup.py build - 运行:进入
build/exe.win-amd64-3.10目录,双击MyApp.exe。
常见问题与解决方案
-
ModuleNotFoundError(缺少模块)- 原因:
cx_Freeze自动检测遗漏了某些依赖。 - 解决: 在
build_exe_options的includes列表中手动添加缺少的模块名。
- 原因:
-
DLL not found或找不到动态链接库- 原因: 某些 C 扩展库(如
numpy,Pillow)依赖外部的 DLL 文件,cx_Freeze没有自动复制它们。 - 解决:
- 简单方法: 将这些 DLL 文件所在的 Python
DLLs目录(C:\Python311\Lib\site-packages\numpy.libs)下的所有.dll文件手动复制到你的build/exe.win-amd64-3.10目录。 - 推荐方法: 使用
binaries选项,你需要先找到这些 DLL 的位置,然后在setup.py中指定。build_exe_options = { "binaries": [ ("path/to/your/dll/file.dll", ".") # 将 dll 复制到 exe 所在目录 ] }
- 简单方法: 将这些 DLL 文件所在的 Python
- 原因: 某些 C 扩展库(如
-
打包后程序启动慢或卡顿
- 原因:
cx_Freeze默认将所有代码打包到一个.exe文件中,首次运行时需要解压,导致延迟。 - 解决: 使用
zip_include_packages选项,它会将指定的包打包成.zip文件,加快启动速度。build_exe_options = { "zip_include_packages": ["numpy", "PIL"], # 将这些包打包成 zip "zip_include_packages": ["*"] # 打包所有包为 zip (谨慎使用) }
- 原因:
-
控制台窗口一闪而过 (GUI 程序)
- 原因: 你忘记在
Executable中设置base="Win32GUI"。 - 解决: 确保你的
Executable定义中包含了base="Win32GUI"。
- 原因: 你忘记在
使用 cx_Freeze 打包 Python 程序的核心流程可以概括为:
- 安装:
pip install cx_Freeze - 创建
setup.py: 这是打包的配置文件。 - 定义
Executable: 指定主脚本和运行模式(控制台/GUI)。 - 配置
options: 使用includes,excludes,include_files等精确控制依赖和数据文件。 - 运行命令:
python setup.py build - 测试: 在目标机器上运行生成的
.exe文件,并根据错误信息调试setup.py。
对于复杂项目,手动处理依赖项和数据文件是保证打包成功的关键,希望这份详细的指南能帮助你顺利完成打包!
