前言
打包的代碼通常都需要寫一個簡單的界面,一般用 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'], )
五、生成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)
五、生成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
