• 将python代码打包成一个app/exe


    前言

      打包的代码通常都需要写一个简单的界面,一般用 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 FilesMicrosoft Visual Studio 
            freeze_support9.0VC
        edistx86Microsoft.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:Anaconda3Libsite-packagesmatplotlibmpl-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:Anaconda3Libsite-packagesmatplotlibmpl-datamatplotlibrc']),
                (r'mpl-dataimages',glob.glob(r'C:Anaconda3Libsite-packagesmatplotlibmpl-dataimages*.*')),
                (r'mpl-datastylelib',glob.glob(r'C:Anaconda3Libsite-packagesmatplotlibmpl-datastylelib*.*')),
                (r'mpl-datafonts',glob.glob(r'C:Anaconda3Libsite-packagesmatplotlibmpl-datafonts*.*')),
                ("",[r"C:Anaconda3Libsite-packagesPyQt5libEGL.dll"]),
                ("platforms",[r"C:Anaconda3Libsite-packagesPyQt5pluginsplatformsqwindows.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 目录下的 platformsqwindows.dll 拷贝至 exe 所在目录,注意保留 platforms 子目录
    • 网上提供的解决方法二:在 data_files 参数中加入两个元祖,元祖中写入(该方法与上面的方法一个作用,他会在你执行打包命令时自动将将 QT 的 bin 目录下的 platformsqwindows.dll 拷贝至 exe 所在目录)
    # 注:路径为你的python的PyQt5的路径
    data_files=[("",
                [r"F:Pythonpython3Libsite-packagesPyQt5libEGL.dll"]),
                ("platforms",
                [r"F:Pythonpython3Libsite-packagesPyQt5pluginsplatformsqwindows.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 目录下的 Libsite-packagesPyInstaller 即可 这样就支持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

                    

  • 相关阅读:
    软件工程概论作业二 电梯调度思路 信1205班 刘权毅 董文轩
    软件工程概论作业一 信1205班 20122561 董文轩
    团队开发第三天(董文轩,苏康奖,常晓杨,刘权毅,刘梦辉,刘若凡)
    软件工程概论作业三 信1205班 董文轩 刘权毅
    IDEA 搭建spring+maven+mybatis+mysql+junit+log4j2
    什么时候需要实现序列化Serializable
    IDEA如何查看maven依赖冲突
    Docker for windows : 安装linux
    Mybatis 分页
    POI java操作OFFICE产品
  • 原文地址:https://www.cnblogs.com/zhuminghui/p/9483627.html
Copyright © 2020-2023  润新知