前言

  打包的代码通常都需要写一个简单的界面,一般用 PyQt 来写。用 PyQt 写界面的方法请戳这里:PyQt5的安装及基本配置    PyQt5教程

  python提供了几个用来打包的模块,主要有 py2app、py2exe、pyinstaller,其中第一个是用来打包来给 mac 用的,后两者是针对于 windows 系统。

关于 py2exe 和 pyinstaller 两者的比较:

  对于 pyinstaller 和 py2exe 两种把 Python 文件打包成 exe 可执行文件的方法,都有各自的优缺点。但是最终目的都是为了在没有 Python 环境下的普通  Windows 系统的电脑中可直接运行。py2exe 的使用方法基本和 py2app 一样,但是本人操作时发现在 mac 中无法用 py2exe 打包成 exe,但是可以用 pyinstaller 打包成 exe,没有尝试过是否可以在 windows 环境下用 py2app 打包成 app。pyinstaller (-F指令下)生成的 exe 文件,集成了所需要的所有资源(所以 exe 文件 相对较大),可直接拷贝到其他电脑中使用。对于 py2exe 来说,限制就比较多了,它所需要用到的外部资源都在 dist 目录下,想要在其他电脑中使用就必须把整个 dist 文件夹都拷贝过去。而且经测试在 64 位机器生成的 exe 无法在 32 位机器上打开使用。

  

py2app打包

注:py2app 方法已在 Mac 环境下测试无误,windows 环境操作时如果遇到问题请自行Google 

一、安装py2app

sudo pip install py2app

二、进入要打包的文件所在的文件夹

cd 。。。。。。。。

三、生成setup.py文件,该文件用于写打包所需要的依赖

py2applet   --make-setup  xxx.py  # xxx.py为项目的启动文件,之后生成的xxx文件就是双击执行的app文件

执行以后目录中会生成 setup.py 文件,用于写入依赖的库。

四、在 setup.py 文件中手动输入需要的依赖

  如果项目很简单,没有导入第三方库和自建模块,可以忽略此步骤。

  下面是setup.py文件的一个例子,手动输入的部分就是在 DATA_FILES 空列表里加自建模块的名字,在 OPTIONS 字典的 includes 对应的空列表中加第三方模块的名字

# python自带的库无需输入,第三方库和自己引入的自写模块需要输入
"""
This is a setup.py script generated by py2applet Usage:
python setup.py py2app
""" from setuptools import setup APP = ['start.py']
#自写模块放在DATA_FILES列表中
DATA_FILES = ['xxx1.py','xxx2.py','xxx3.py']
# 第三方库放在OPTIONS下的includes对应的列表中
OPTIONS = { 'includes': ['sip', 'PyQt5.QtCore', 'PyQt5.QtWidgets'],} setup(
app=APP,
data_files=DATA_FILES,
options={'py2app': OPTIONS},
setup_requires=['py2app'],
)

示例setup.py

五、生成app

# 自己开发,打包速度快。(因为本机安装了依赖库,所以可以直接运行)
python setup.py py2app -A # 给其他没有 sdk 的电脑使用,包括 lib 库。(没有安装 sdk 的电脑使用,需要去掉 -A,将把所有的依赖全部打包。)
python setup.py py2app 

  之后会生成 build 和 dist 两个文件夹,启动文件在 dist 下,双击就可以执行。

注:如果发现有问题,在重新进行上述步骤前最好先删除 build 和 dist 两个文件夹

rm -rf build dist

py2exe

  首先声明,py2exe 在高版本的 python 环境下可能会出现不支持的情况,我在打包的时候只支持到 python3.4,不清楚目前支持到哪个 python 版本。

注:本人在 win10 下用 py2exe 打包的含有 PyQt5 写界面的程序无法正常运行,遇到的问题很多,如果程序中用到了 PyQt5,推荐选用 pyinstaller 打包

一、安装py2exe

pip install py2exe

二、进入项目目录

cd xxxxxxxxx

三、在项目根目录中自行创建setup.py文件

  该文件的作用与 py2app 的 setup.py 文件一样,只不过需要自己手动创建,区别在于你可以任意命名该文件(如 woshinibaba.py)

四、在 setup.py(woshinibaba.py) 文件中写入需要的依赖

文件中基本格式为

# -*- coding: utf-8 -*-

from distutils.core import setup
import py2exe setup(
# console和windows分别代表控制台和图形界面,按需求选择
#console = [{"script" : 'comtrade.py'}],
windows = [{"script":"comtrade.py", "icon_resources": [(1, "logo.ico")]} ],
name = 'comtrade',# 生成的exe文件名
version = '1.0',
options={}, # 括号内填入的为项目所需的依赖库和会造成报错的文件
data_files={})# 括号内输入的为项目所需的依赖文件
# version ,description,name不是必须要写的。

其他参数:

  • dist_dir           打包生成的文件放在 dist 下,可设置存放目录(一般没有特殊要求,可以不需修改。可使用相对路径)
  • Compressed    默认为 0,1 为指定压缩文件(library.zip)的行为;0 为不压缩。
  • Zipfiles           配置共享压缩文件的生成目录和文件名,默认是在目录 dist 下生成一个  “library.zip” 文件,打包了 .exe 文件运行需要的 .pyd  和 .dll 文件(不包含配置文件等)。
  • Optimize         打包优化,合法值是字符串('','O','OO')或者整型数字 (0, 1, or 2)。
    • 为 0 时:不进行优化,压缩包大小较大,打包的编译文件为 .pyc;
    • 为 1 时:进行少量优化,压缩包大小略小,打包的编译文件为 .pyo;
    • 为 2 时:优化级别最高,压缩包大小也明显变小,打包的编译文件为 .pyo。
  • Bundle_files     打包绑定,64位不支持此属性。
    • 为 0 时:pyd 和 dll 文件不会被打包到 exe 文件中;
    • 为 1 时:pyd 和 dll 文件会被打包到 exe 文件中,且不能从文件系统中加载 python 模块;
    • 为 2 时:pyd 和 dll 文件会被打包到 exe 文件中,但是可以从文件系统中加载 python 模块。
    • 注:
      • .py:编写的源文件。
      • .pyc:编译过的二进制代码文件。如果导入一个模块,python 将创建一个 *.pyc 文件,文件内为二进制码,这样可以在再次导入时更容易(更快)。
      • .pyo:当优化等级 (-O) 开启时生成的 *.pyc 文件。
      • .pyd:相当于一个 windows dll 文件。实际上 .pyd 文件就是 dll 文件,只是略有不同。
  • Date_files       文件可执行文件所需数据。在 python27 中,需要的 MSVCP90.dll 不能单独发布,必须确保 py2exe 复制所有的三个 dll 文件和 manifest 文件到工程目录 dist 下,并且放在一个名为 'Microsoft.VC90.CRT' 的子目录下。
    • 参考做法为:

      from glob import glob  
      
      data_files  = [
      ("Microsoft.VC90.CRT",
      glob(r'C:\Program Files\Microsoft Visual Studio
      freeze_support9.0\VC\redist\x86\Microsoft.VC90.CRT\*.*'))
      ]
  • ascii               
    • 为 0 时:不包含编码和解码器;
    • 为 1 时则反之。
    • 假设出现 QPixmap::scaled: Pixmap is a null pixmap 问题,这是由于 PyQt 和 qt 都是默认的 png 格式的图片,打包后,会找不到 jpg 格式的图片,所以在打包过程中需要把 PyQt4 文件中的imageformats 文件夹下的 dll 文件导入。这是 jpg 格式的图片需要的插件。
  • 类标识符无属性,产生的CLSID无属性。

typelibs

列表:需要包含的gen_py产生的typelibs

  • 多进程打包遇到的程序不正常执行问题,需要在多进程之前调用 freeze_support() 函数。经试验,最好在函数开始执行的时候,首先调用此函数。

具体例子:

# -*- coding: utf-8 -*-

# 必须写的倒入模块
from distutils.core import setup
import py2exe # 可以不用写的部分
"""
#We need to import the glob module to search for all files.
import glob
import sys
#this allows to run it with a simple double click.
sys.argv.append('py2exe')
""" # 项目中需要用到的第三方库写入includes所对应的列表中
# 项目中用不到的会造成报错的文件放在excludes所对应的列表中,若报错的是dll文件,放入dll_excludes所对应的列表中
# 下面是示例:
opts= {
'py2exe':{ "includes" : [ "sip", "matplotlib.backends", "matplotlib.backends.backend_tkagg",
"matplotlib.figure","numpy", "matplotlib.pyplot", "pylab", "six",
"matplotlib.backend_bases", 'scipy.special._ufuncs_cxx',
"scipy.integrate","scipy.integrate.quadpack","scipy.sparse.csgraph._validation"],
"excludes" : ['_gtkagg', '_tkagg', '_agg2', '_cairo', '_cocoaagg',
'_fltkagg','_gtk', '_gtkcairo'], "dll_excludes":['libgdk-win32-2.0-0.dll','libgobject-2.0-0.dll',"MSVCP90.dll",]
}
} #项目中需要用到的外部文件依赖放入列表中,格式为[(),(),()]
# 元祖中第一个元素是打包时要创建的文件夹名,如果要放在exe文件的同目录下就用"",第二个元素是该依赖文件的路径
data_files= [(r'mpl-data',glob.glob(r'C:\Anaconda3\Lib\site-packages\matplotlib\mpl-data\*.*')),
#Because matplotlibrc does not have an extension, glob does not findit (at least I think that's why)
#So add it manually here:
(r'mpl-data',[r'C:\Anaconda3\Lib\site-packages\matplotlib\mpl-data\matplotlibrc']),
(r'mpl-data\images',glob.glob(r'C:\Anaconda3\Lib\site-packages\matplotlib\mpl-data\images\*.*')),
(r'mpl-data\stylelib',glob.glob(r'C:\Anaconda3\Lib\site-packages\matplotlib\mpl-data\stylelib\*.*')),
(r'mpl-data\fonts',glob.glob(r'C:\Anaconda3\Lib\site-packages\matplotlib\mpl-data\fonts\*.*')),
("",[r"C:\Anaconda3\Lib\site-packages\PyQt5\libEGL.dll"]),
("platforms",[r"C:\Anaconda3\Lib\site-packages\PyQt5\plugins\platforms\qwindows.dll"])] # 将上述参数传入setup中,console和windows分别代表控制台和图形界面,按需求选择
setup(
#console = [{"script" : 'comtrade.py'}],
windows = [{"script":"comtrade.py", "icon_resources": [(1, "logo.ico")]} ],
name = 'comtrade',
version = '1.0',
options=opts, data_files=data_files)

setup.py(woshinibaba.py)

五、生成exe 

python setup.py app2exe

执行完毕后会生成build和dist文件夹,启动文件在dist文件夹下

py2exe报错解决

1. 执行打包命令时报错 Missing run-py3.5-win-amd64.exe

  • 原因:py2exe 最高只支持到 python3.4,如果你用的 3.5 或更高的版本就会出现这个问题
  • 解决方法:创建个虚拟环境安装 python3.4,然后 pip install 所有项目需要的第三方库后重新进行一边打包操作

2. 执行打包命令时报错 indexError: tuple index out of range

  • 原因:py2exe 最高只支持到 python3.4,如果用更高的版本就会出现这个问题
  • 解决方法:创建个虚拟环境安装 python3.4,然后 pip install 所有项目需要的第三方库后重新进行一边打包操作

3. 执行打包操作时报错 (忘了具体报错信息,意思时递归深度超过最大限制)

  • 原因:py2ex e最高只支持到 python3.4,如果你用的更高的版本就会出现这个问题
  • 解决方法:创建个虚拟环境安装 python3.4,然后 pip install 所有项目需要的第三方库后重新进行一边打包操作

4. 打包 ok,但双击可执行文件时报错 Failed to execute script xxx

  • 原因:去 log 文件中查看,会发现报错信息为 no module named xxx,意思为项目中缺少 xxx 模块
  • 解决方法:pip install ,如果你确定你已经安装了该模块,那就在 setup.py(woshinibaba.py)文件最上面 import 该模块

5. 打包 ok,但双击可执行文件时弹窗报错 This application failed to start because it could not find or load the Qt platform plugin "windows".

注:这是我遇到的一个最大的问题,问题原因和 PyQt5 有关目前尚未找到解决方案,然后选用了 pyinstaller

  • 疑似原因一:python3.4 不支持 PyQt5
  • 本人理解:python3.4 环境下用 pip install PyQt5,报错说找不到该模块,但是可以运行 pip install pyqt,而 pyqt 指得是 PyQt4,两者是不一样的。在 pycharm 中将其升级为 PyQt5,惊奇的发现我的python 环境变成 python3.7了?!在升级 pyqt 的同时将我的 python 都升级了?但是 py2exe 不支持 python3.7 啊,WTF?!最后本人不了了之选择了pyinstaller
  • 疑似原因二:没有将 PyQt5 写入环境变量
  • 网上提供的解决方法一:将 QT 的 bin 目录下的 \platforms\qwindows.dll 拷贝至 exe 所在目录,注意保留 \platforms 子目录
  • 网上提供的解决方法二:在 data_files 参数中加入两个元祖,元祖中写入(该方法与上面的方法一个作用,他会在你执行打包命令时自动将将 QT 的 bin 目录下的 \platforms\qwindows.dll 拷贝至 exe 所在目录)
# 注:路径为你的python的PyQt5的路径
data_files=[("",
[r"F:\Python\python3\Lib\site-packages\PyQt5\libEGL.dll"]),
("platforms",
[r"F:\Python\python3\Lib\site-packages\PyQt5\plugins\platforms\qwindows.dll"])]
  • 网上提供的解决方法三:改变系统变量(变量值为你的 python 所在的目录下的 PyQt5 的目录)

                    

  

pyinstaller

  首先要声明,pyinstaller 在高版本的 python 环境下可能会出现不支持的情况,我在打包的时候只支持到 python3.5,不清楚目前支持到哪个 python 版本。如果你的 python 已是3.5以上的版本,建议创建一个虚拟环境后安装 python3.5,再自行安装上程序所依赖的库比如 requests 等等,在新环境中进行打包。

注:pyinstaller 方法已在 win10、win8 和 Mac环境下测试无误,但打包程序本身会因为你的程序的不同而需要有些许改动,文章末尾会有一些我遇到过的报错的解决方法,出现问题可自行Google

一、安装pyinstaller

pip install pyinstaller

二、切换到工作目录

cd xxxxxxxxxxx

三、打包命令

  与上面两个不同的是,pyinstaller 不需要自己写 setup.py 文件,只需要在工作目录中输入打包命令即可。最后会生成 build 和 dist 文件夹,启动文件在 dist 文件夹下。

命令格式:

pyinstaller [项目启动文件]

其他参数(按需求选择):

  • -F   表示在 dist 文件夹下只生成单个可执行文件(内部包含所有依赖),不加默认会在 dist 生成一大堆依赖文件+可执行文件。
  • -D   与 -F 相反用法
  • -W  表示去掉控制台窗口,如果你的程序是有界面的,可以不写这个参数。但是测试情况下建议先加上这个参数,因为如果打包不成功,运行时报错信息会在控制台上输出,没有控制台就看不到报错信息。
  • -c   表示去掉窗框,使用控制台
  • -p    表示自己定义需要加载的类路径,项目中包含多个自建模块的时候需要加上 -p aaa.py -p bbb.py -p ccc.py
  • -i     表示可执行文件的图标,后面跟图标的路径
  • --hidden-import  后面跟模块名如 queue,用于告诉打包程序某个模块我用不着你不用打包进去

  打包完毕后在 dist 文件夹下双击项目启动文件就可以了

pyinstaller报错解决

1.执行打包命令时报错  IndexError: tuple index out of range

  • 原因:官网目前的版本是 3.2.1 只支持到 python3.5 ,高版本的 python 尚不支持,
  • 解决方法:网上有大神提供了完善版的代码——官网源码里有 https://github.com/pyinstaller/pyinstaller 替换你 python 目录下的 \Lib\site-packages\PyInstaller 即可 这样就支持python3.6了 不过是开发版,可能还不完善。

  作者建议最好还是用虚拟环境下的 python3.5 进行打包。


2.执行打包命令时报错 ImportError: No module named 'queue'

  • 原因:尚不清楚
  • 解决方法:如果该模块你用不到,可以在执行打包命令时用 --hidden-import 不打包进去。如果程序中需要该模块,在主文件最上面写上 improt queue

3.打包命令执行成功,但双击可执行程序弹出报错窗口failed to excute script xxx

  • 原因:打包时内部缺少了某个依赖,这时需要看看控制台打印了什么报错信息,打包时加了 -w 参数的请再打包一次记得去掉 -w
  • 现象:基本都是在控制台上发现报错 No module named 'xxxxx',如 No module named 'queue' 或者 ModuleNotFoundError: No module named 'PyQt5.sip'
  • 解决方法:同2,如果该模块你用不到,可以在执行打包命令时用 --hidden-import 不打包进去。如果程序中需要该模块,在主文件最上面写上 improt xxxxx。如 import queue 或 import PyQt5.sip

将python代码打包成一个app/exe的更多相关文章

  1. windows环境下把Python代码打包成独立执行的exe

    windows环境下把Python代码打包成独立执行的exe可执行文件   有时候因为出差,突然急需处理一批数据.虽然写好的脚本存储在云端随用随取,然而编译的环境还需要重新搭建,模块也需要重新装载,从 ...

  2. 用pyinstaller把python代码打包成exe可执行文件

    优点: 1. pyinstaller 是跨平台的可以用在linux和windows系统上 2. 操作非常简单,几个命令就搞定了,这个比py2exe容易用多了 缺点: 1. 打包后的体积过大,因为要带p ...

  3. windows环境下把Python代码打包成独立执行的exe可执行文件

    有时候因为出差,突然急需处理一批数据.虽然写好的脚本存储在云端随用随取,然而编译的环境还需要重新搭建,模块也需要重新装载,从头到尾这么一遍下来,也是要花费可观的时间成本的. 有没有什么办法,可以让.p ...

  4. Python代码打包成exe可执行程序

    首先,打包成exe可执行程序是针对windows平台来说的. 目前比较主流的打包工具就是pyinstaller. 参考:Using PyInstaller 首先安装pyinstaller: pip i ...

  5. 用PyInstaller把Python代码打包成单个独立的exe可执行文件

    之前就想要把自己的BlogsToWordpress打开成exe了.一直没去弄. 又看到有人提到python打开成exe的问题. 所以打算现在就去试试. 注:此处之所有选用BlogsToWordpres ...

  6. python代码打包成exe文件

    1.准备工作 1.安装pywin32.pyinstaller 2.准备好ico文件 找一个png格式的图片,使用png2ico脚本生成包含以下6个尺寸的ico文件:128×128 64×64 48×4 ...

  7. win7下用PyInstaller把Python代码打包成exe文件

    2013-11-05 22:02:14|   1.安装 使用PyInstaller需要安装PyWin32. 下载与Python对应的PyInstaller版本,解压后就算安装好了. 例如,安装了PyI ...

  8. Python 程序打包成 exe 可执行文件

    Python 程序打包工具 Python 是一个脚本语言,被解释器解释执行.它的发布方式: .py 文件:对于开源项目或者源码没那么重要的,直接提供源码,需要使用者自行安装 Python 并且安装依赖 ...

  9. 将 Python 程序打包成 .exe 文件

    1.简介 做了一个excel的风控模板,里面含有宏,我用python的第三方xlwings部署到linux后发现,linux环境并不支持xlwings. Python 程序都是脚本的方式,一般是在解析 ...

随机推荐

  1. python 模块学习

    一.from django.contrib.auth.hashers import make_password 通过函数名即可发现,主要有两个函数,分别是创建密码和验证 用法 ps = " ...

  2. Roslyn如何实现简单的代码提示

    假如需要实现一个代码编辑器,其中一个很重要的功能是实现代码提示,类似VS的代码智能提示.下面用Roslyn编译器来实现一个简单的代码提示功能. 代码提示,首先必须需要知道对象的类型信息,然后通过迭代获 ...

  3. 【iCore4 双核心板_ARM】例程二十六:LWIP_MODBUS_TCP实验——电源监控

    实验现象: 核心代码: int main(void) { system_clock.initialize(); led.initialize(); adc.initialize(); delay.in ...

  4. Vue:在vue-cli中使用Bootstrap

    一.安装jQuery Bootstrap需要依赖jQuery,所以引用Bootstrap之前要先引用jQuery,使用下面的命令引用jQuery: npm install jquery --save ...

  5. 基于PHP给大家讲解防刷票的一些技巧

    刷票行为,一直以来都是个难题,无法从根本上防止. 但是我们可以尽量减少刷票的伤害,比如:通过人为增加的逻辑限制. 基于 PHP,下面介绍防刷票的一些技巧: 1.使用CURL进行信息伪造 $ch = c ...

  6. 135、JS和Android交互范例

    很简单的直接上代码 <uses-permission android:name="android.permission.INTERNET" /> assets/web. ...

  7. 安装 RabbitMQ

    Ubuntu 16.04 安装 RabbitMQ #1 更新 $ sudo apt-get update $ sudo apt-get upgrade #2 安装Erlang $ cd /tmp $ ...

  8. 六、Sql Server 基础培训《进度6-更新删除(实际操作)》

    知识点: 假设,创建表test1,test2. drop table test1 create table test1 ( FID int identity(1,1), FBillNo varchar ...

  9. Timer和时间调度

    Timer作为JDK提供的util工具,不太适合作为周期调度任务,只适合简单的定时操作(按照一定时间频率出发任务),在java的领域解决方案中,Quartz无疑是翘楚. Timer的调度方法有: pu ...

  10. php 判断手机号 和 手机号中间四位以**** 代替

    代码: //自定义函数手机号隐藏中间四位 function get_phone($str){ $str=$str; $resstr=substr_replace($str,'****',3,4); r ...