自己写好的python程序在自己的python环境中运行没有问题。但是如果要发布给别人使用,那么对方也需要有python环境。否则就需要将我们的python程序发布为一个可执行文件。

PyInstaller

PyInstaller是一个十分有用的第三方库,它能够在Windows、Linux、Mac OS X 等操作系统下将 Python 源文件打包,通过对源文件打包, Python 程序可以在没有安装 Python 的环境中运行,也可以作为一个独立文件方便传递和管理。
PyInstaller 的官网:http://www.pyinstaller.org/

安装

使用 pip 命令就可以完成安装:

pip install pyinstaller

不过可能国外的源被墙了,这里还可以指定第三方的源来安装:

pip install -i https://mirrors.163.com/pypi/simple pyinstaller

安装完成后,会生成一个pyinstaller.exe的文件在你的Scripts文件夹里,就是pip.exe的那个文件夹。之后就用这个来打包我们的程序。还有一个文件是pyi-makespec.exe也是的。

直接打包程序

使用下面的命令将程序打包:

pyinstaller <主程序名>.py

打完完成后会生成 build 和 dist 两个文件夹。其中,build 目录是 pyinstaller 存储临时文件的目录,可以安全删除。最终的打包程序在 dist 内部的<主程序名>目录中。另外还有一个 <主程序名>.spec 的文件,下面会讲到,也是可以删除的。
注意:这样打包你的程序不能包含其他资源文件。没有import的文件应该都不会打包进去的,貌似程序本身也没有办法判断要包含哪些资源,总不能一句一句去分析你的源码吧。
其实这里手动把你的资源文件copy过去也就OK了,不过这个不是正规路子。

生成规范文件再打包

通过编辑一个规范文件,告知程序需要包含哪些资源文件,通过这个规范文件进行打包。生成默认规范文件的命令:

pyi-makespec <主程序名>.py

其实,之前直接打包的时候,也是先生成默认的规范文件的,然后在根据这个规范文件进行打包。这里只是把这个过程分成了2步。中间你可以修改这个规范文件,然后再进入下一步的打包。
默认的文件内容如下:

# -*- mode: python -*-

block_cipher = None

a = Analysis(['showlist.py'],
             pathex=['I:\\Python自动化开发学习\\作业\\week1\\多级菜单'],
             binaries=[],
             datas=[],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          exclude_binaries=True,
          name='showlist',
          debug=False,
          strip=False,
          upx=True,
          console=True )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               name='showlist')

修改datas这个变量,把你的资源文件添加到后面的列表里去。下面的例子中,我先定义一个变量added_files,然后将这个列表赋值给datas。列表元素是元组,前面是你的资源的路径(这里是相对路径了),后面是要放到打包文件的哪个位置具体如下:

# -*- mode: python -*-

block_cipher = None

added_files = [
    ('poetry', 'poetry'),
    ('list.txt', '.'),
]
a = Analysis(['showlist.py'],
             pathex=['I:\\Python自动化开发学习\\作业\\week1\\多级菜单'],
             binaries=[],
             datas=added_files,
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          exclude_binaries=True,
          name='showlist',
          debug=False,
          strip=False,
          upx=True,
          console=True )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               name='showlist')

通过规范文件打包,规范文件修改后之后,使用下面的命令指定规范文件进行打包:

pyinstaller <规范文件名>.spec

执行完成后,现在打包好的程序里就包含了我们添加的资源文件了。其实效果和我们自己时候手动复制是一样的。
会修改规范文件,就不需要用到下面的参数了。

有用的参数

使用-h可以看到参数的说明,下面是几个比较有用的参数。
另外使用参数就不需要用使用规范文件了。使用了参数的本质还是先生成一个规范文件,这个规范文件会根据我们的参数有一些变化,然后还是通过规范文件进行打包。可以通过使用参数打包后查看自动生成的规范文件进行比较来验证。

生成单个文件(-F, --onefile)

命令:

pyinstaller -F <主程序名>.py
或
pyinstaller <主程序名>.py -F

这里我是试出来直接打包不包含资源文件的程序。成功后dist文件夹下面就只会有一个可执行文件,而且大小也比之前的文件夹小了很多。不过网上说启动程序会变慢,自己把握把。

如果是包含资源文件的规范文件使用-F参数打包,最后得到的还是一个目录。

指定资源文件(--add-data 【SRC;DEST or SRC:DEST】)

前面是源,后面对目的,中间是分隔符。windows系统使用分号(;),Linux系统使用冒号(:)。并且这个参数可以多次使用。下面就是添加了2个资源文件:

pyinstaller showlist.py --add-data poetry;poetry --add-data list.txt;.

最后的效果还是和上面使用规范文件再打包一样,感觉还是用规范文件的方式好一点。这里可以比较一下系统自动生成的规范文件。
这里尝试结合-F一起使用,但是生成的单文件里测试下来还是没有包含资源文件。大概就是不能连资源文件一起打包成单一文件的。不过把资源文件复制过去还是可以用的。也就是你的主程序还是单文件的,但是资源文件独立在外面。

指定图标(-i 【FILE.ico or FILE.exe,ID or FILE.icns】, --icon 【FILE.ico or FILE.exe,ID or FILE.icns】)

指定个图标还是蛮有用的,不过试下来,单文件还是貌似无效。只有用文件夹,然后里面主程序的图标会变成你指定的图标。

pyinstaller <主程序名>.py -i <图标>.ico

同样的,规范文件里也是有地方指定图标的:

exe = EXE(pyz,
          a.scripts,
          exclude_binaries=True,
          name='showlist',
          debug=False,
          strip=False,
          upx=True,
          console=True , icon='name.ico')

小结

  • 推荐先生成规范文件,然后编辑一下,在通过规范文件来打包
  • 还是不要生成单文件了,我试下来也比较鸡肋
  • 自己用或者和别人交流也不用打包了,几十k的代码包下来十几兆。因为考虑到没有python环境,应该是把要用到的库也都包进去了
  • 最后打包发布给外行用用还是不错的,在搞个图标包装一下,nice。

展开-wx模块

有一个wxPython模块,是用来做界面的。
做出窗口界面,包装好我们的python程序,最后再打包成可执行文件来发布。这样一个python软件就出来了。