python程序怎么做成一键执行的脚本-目标环境也不用安装python环境

1,338 阅读5分钟

将 Python 程序打包成一键可执行的程序,使其无需手动安装 Python 环境,可以使用一些工具来创建独立的可执行文件。

常用的工具包括 PyInstaller、py2exe 和 cx_Freeze 本文主要介绍 Pyinstallser

  • PyInstaller

    • 特点:将 Python 代码和依赖的库打包成单个可执行文件,适用于多平台(Windows、Linux、macOS)。
    • 优点:容易使用,支持多平台,可以处理复杂的依赖关系。
    • 缺点:打包后的文件可能较大,有时对于某些第三方库的支持可能不够完整。
  • py2exe

    • 特点:专门用于将 Python 脚本打包为 Windows 可执行文件(.exe 文件)。
    • 优点:生成的可执行文件可以在 Windows 上独立运行,无需安装 Python 解释器。
    • 缺点:只支持 Windows,对于跨平台开发不适用。
  • cx_Freeze

    • 特点:类似于 PyInstaller,可以将 Python 代码和依赖的库打包成可执行文件。
    • 优点:支持多平台(Windows、Linux、macOS),可以生成独立的可执行文件。
    • 缺点:配置较为复杂,有时需要手动指定依赖的库和模块。

使用 PyInstaller 打包 Python 程序 - - 生成的可执行文件是独立的,不需要 Python 环境。你可以将这个文件发送给用户,用户只需双击即可运行程序。

使用之前

安装 PyInstaller: 首先,确保你的 Python 环境中安装了 PyInstaller。你可以使用 pip 来安装它:

```
pip install pyinstaller
```
  • 编写你的 Python 程序: 假设你的 Python 程序文件名是 my_program.py。提前在环境上运行 保证该程序可用

基础配置项使用

  • 使用 PyInstaller 打包: 在命令行中运行以下命令来打包你的程序:

    pyinstaller --onefile my_program.py
    

    这条命令会生成一个独立的可执行文件。--onefile 选项表示将所有代码和依赖打包成一个单独的可执行文件。

  • 找到生成的可执行文件: 打包过程完成后,PyInstaller 会在 dist 目录下生成一个可执行文件。对于上面的例子,生成的文件路径通常是 dist/my_program(Windows 上是 dist\my_program.exe)。

创建图标和指定其他选项

如果你想指定图标或其他打包选项,可以使用 PyInstaller 提供的更多选项。例如:

pyinstaller --onefile --icon=my_icon.ico --name=MyProgram example.py
# 这条命令会将你的程序命名为 `MyProgram` 并使用 `my_icon.ico` 作为图标。(在windows 上 exe 会有一个图标以及程序名)

关于代码依赖关系

包含多个 Python 文件的项目,可以使用 PyInstaller 打包整个项目。PyInstaller 会自动处理依赖关系,并将所有相关文件打包到一个可执行文件中。

  • 项目结构: 假设你的项目结构如下 其中 main.py 是你的主入口文件:

    my_project/
    ├── main.py
    ├── module1.py
    ├── module2.py
    ├── utils/
    │   ├── helper.py
    │   └── __init__.py
    └── resources/
        └── data.txt
    
  • 使用 PyInstaller 打包项目: 在项目根目录下打开终端,并运行以下命令:

    pyinstaller --onefile main.py
    
  • 处理附加资源: 如果你的项目中包含非 Python 文件(如 resources/data.txt),你需要告诉 PyInstaller 包含这些文件。你可以使用 --add-data 选项:

    pyinstaller --onefile --add-data "resources/data.txt:resources" main.py
    在 Windows 上,路径分隔符使用分号 `;` 而不是冒号 `:`:
    pyinstaller --onefile --add-data "resources/data.txt;resources" main.py
    

    可以使用 --add-data 选项多次添加这些文件和目录:

    pyinstaller --onefile \
        --add-data "data/241.log:data" \
        --add-data "data/242.log:data" \
        --add-data "data/other/301.log:data/other" \
        --add-data "data/other/302.log:data/other" \
        --add-data "more_data/401.log:more_data" \
        --add-data "more_data/402.log:more_data" \
        main.py
    

    或者使用通配符来添加整个目录:

    pyinstaller --onefile \
        --add-data "data:data" \
        --add-data "more_data:more_data" \
        main.py
    

    或者使用*号

    pyinstaller --onefile \
    --add-data "data/*.log:data" \
    --add-data "data/other/*.log:data/other" \
    --add-data "more_data/*.log:more_data" \
    main.py
    
  • 配置 spec 文件(可选) : PyInstaller 会生成一个 .spec 文件,你可以对其进行修改以更好地控制打包过程。生成 .spec 文件后,你可以编辑它并使用该文件进行打包:

    生成 .spec 文件:

    pyinstaller --onefile --add-data "resources/data.txt:resources" main.py
    

    编辑生成的 main.spec 文件,根据需要添加更多资源或修改配置,然后使用该文件进行打包:

    pyinstaller main.spec
    

生成的文件和目录

  1. dist 目录dist 目录包含打包后的可执行文件。例如,如果你的主脚本是 main.py,那么你会在 dist 目录下看到一个名为 main 的可执行文件(在 Windows 上是 main.exe)。
  2. build 目录build 目录包含 PyInstaller 在打包过程中生成的临时文件。通常你不需要关心这个目录的内容。
  3. spec 文件.spec 文件是 PyInstaller 用于配置打包过程的脚本文件。你可以根据需要修改这个文件,然后使用它来定制打包过程。

注意事项

  • 大小:生成的可执行文件可能会比较大,因为它包含了 Python 解释器和所有依赖项。
  • 兼容性:在一个操作系统上生成的可执行文件不能在其他操作系统上运行。例如,在 Windows 上打包的 main.exe 不能在 Linux 或 macOS 上运行。你需要在每个目标操作系统上分别打包。
  • 路径:如果你的程序依赖于相对路径的资源文件,确保在打包后正确处理这些路径。使用 sys._MEIPASS 来访问打包后的资源文件。参考以下resource_path示例代码来正确处理路径:
import os
import sys

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    try:
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

def main():
    data_file_path = resource_path("resources/data.txt")
    with open(data_file_path, "r") as file:
        data = file.read()
        print(data)

if __name__ == "__main__":
    main()