【pyinstaller 打包python 教程 】

文章目录

  • 基础语法
    • 参数
      • 必选的参数
      • 可选的参数:
  • 打包详细步骤
    • 打包多文件
    • 打包的资源路径问题

基础语法

此处参考官网说明:

pyinstaller [options] script [script …] | specfile

所以最简单的用法如下,即可打包

pyinstaller myscript.py

这个操作即可完成打包,会执行如下操作:

  • Writes myscript.spec in the same folder as the script.

  • Creates a folder build in the same folder as the script if it does
    not exist.

  • Writes some log files and working files in the build folder.

  • Creates a folder dist in the same folder as the script if it does not
    exist.

  • Writes the myscript executable folder in the dist folder.
    一句话总结下就是会跟脚本同一个目录下生成 myscript.spec ,build 目录 dist目录
    其中可执行程序就在dist目录里

一般情况,我们只需要打包主python脚本,如果你在pyinstaller后面包含了多个脚本,那么这些脚本都会包含在输出文件里

另外生成的myscript.spec 也可以用来生成可执行程序

pyinstaller myscript.spec

参数

此处介绍几个常用的,更多的还是请查看官网

必选的参数

脚本或者spec文件

可选的参数:

  • –distpath DIR 指定的app的输出路径,默认情况下是dist目录
  • -D 打包生成一个文件夹
  • -F 打包只生成一个可执行文件 ,这种所有文件都在可执行程序里,打开程序时需要解压缩,速度很慢
  • -p DIR import的时候的搜索路径
  • –hidden-import 同上也是搜索路径,但是最后的输出是不可见的,也就是不会把搜索的脚本输出到可执行文件里

打包详细步骤

首先说明一下我的代码目录,这是用来打包智能翻译的,所以resource中还包括了语料文件和模型文件

src 所有源码的路径
—main.py frozendir.py 以及其他目录文件
resource
—dataset 这是存放语料的路径
—modle_save 模型和词库存放路径

打包多文件

找到主入口脚本以main.py举例,直接

 pyinstaller main.py

pyinstaller会寻找所有main的依赖文件和依赖文件的依赖文件,不论引用了多少个文件,我们只需要简单的打包主文件即可
但是要注意一点,操作的时候发现,如果打包的时候,导入的包的路径,在你打包路径的上一层,比如main.py在src下,而其他文件引入代码是通过from src. xxx import xxx,这时候必须手动添加上这层路径,此时使用 --hidden-import 引入,如下:

–hidden-import=src --paths="E:\code\seq2seq”

当然不引入,启动也一定会失败,报 类似 no moudule named XXX的错误

打包的资源路径问题

打包的时候最头痛的是路径问题,比如程序里需要引用的图片和输入文本文件等,这些文件在我们用ide执行脚本的时候,路径是相对的或者绝对的,无论怎么写都没问题,但是到了打包的程序包里,会有如下问题:
用-F打包成一个文件,所有的资源会被解压缩到一个临时文件里,根本不知道路径是什么
打包的时候用相对路径,但是脚本执行的时候获取的路径是会根据运行脚本的位置在变化,无法锁死路径。
当然官网也给出了解决方案:

  1. frozen 路径

首先在源码的最外层比如我们此处是src,写一个脚本,用于frozen 路径,获取程序执行时的绝对路径

def get_base_dir():
    if getattr(sys, 'frozen', False):
        base_dir = os.path.dirname(os.path.abspath(sys.executable))
    elif __file__:
        base_dir = os.path.dirname(os.path.abspath(__file__))

    return base_dir

这样无论你如何执行,路径都不会再动了

  1. 其他文件配置的路径都基于此
raw_file_path = os.path.join(base_dir, r".\resource\dataset\cmn.txt")
raw_zip_path = os.path.join(base_dir, r".\resource\dataset\cmn-eng.zip")
model_save_path = os.path.join(base_dir, r'.\resource\model_save\ai_net.pkl')

src_vocab_save_path = os.path.join(base_dir, r'.\resource\model_save\src_vocabulary.pkl')
tgt_vocab_save_path = os.path.join(base_dir, r'.\resource\model_save\tgt_vocabulary.pkl')

这样路径就能被固定下来了,例如这里resource的目录是、在可执行程序里的同级目录下的resource目录下,当然resource在打包的时候也需要配合打包到这个目录,下面是怎么配合打包resource目录。

  1. 打包的时候,需要指定resource的路径打包到可执行程序的同级目录下
 pyinstaller.exe  main.py --distpath="..\exe"  --add-data="E:\work\code\seq2seqattention\resource\dataset\*;.\resource\dataset\."  --add-data="E:\work\code\seq2seqattention\resource\model_save\*;.\resource\model_save"

4.最后一点就是注意资源文件如果包含多层目录,多层的打包方式,可以详细看下上面的例子

实操的时候发现pyinstaller 打包的时候,如包含多层就必须一对一都写入,否则打出来的路径会缺失
比如resource下面包含了dataset和model_save,必须一一对应的打包,否则很可能就缺失了一层

5.所有都写完之后,可以现在cmd活着powershell等上执行以下,看是否报错。
如果直接点击打开,很可能闪退,什么都看不到

此时如果是打包到一个目录的方式,就可以在dist目录(未指定打包到其他目录的话)下看到main.exe也可以看到resource目录了
下面是我完成打包一个机器翻译的源码的过程:

 pyinstaller.exe  main.py --distpath="..\exe"  --add-data="E:\work\code\seq2seqattention\resource\dataset\*;.\resource\dataset\."  --add-data="E:\work\code\seq2seqattention\resource\model_save\*;.\resource\model_save"

你可能感兴趣的:(python,python)