上週五好不容易用Python内建的Tkinter将操作介面拉好且测试OK,没想到在打包成执行档(.exe)这边花了一个上午,所以纪录一下自己的碰壁流程。
工作环境:
-Windows 10, Windows Server 2019
-Anaconda 2020.02
-Python 3.6.10
问题描述:
如何用PyInstaller打包Python代码为执行档(.exe)打包过程碰上的问题以及如何排除先安装PyInstaller:pip install pyinstaller
打开Anaconda Prompt (anaconda3),并且将当前位置切至.py档存放路径:cd C:\Users\*\Documents\GUI-20200323
输入打包代码,我要打包的是main.py。一般的教程都只到这边就停了,但后面才蛋疼:pyinstaller main.py
4. 问题:RecursionError: maximum recursion depth exceeded
File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 253, in visit return visitor(node) File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 263, in generic_visit self.visit(value) File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 253, in visit return visitor(node) File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 263, in generic_visit self.visit(value) File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 253, in visit return visitor(node) File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 263, in generic_visit self.visit(value) File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 253, in visit return visitor(node) File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\ast.py", line 257, in generic_visit for field, value in iter_fields(node):RecursionError: maximum recursion depth exceeded
突然蹦出这些有的没的,解决方法很简单,看一下.py档存放路径是不是出现了main.spec这个由PyInstaller自动产生的配置文件,用笔记本打开后新增下面两行代码后储存离开,然后保险起见将build和dist两个资料夹删除:
原因在于超过递迴限制,我也看不懂这什么意思。[8]
# -*- mode: python ; coding: utf-8 -*-import sys #我是新增的sys.setrecursionlimit(9000000) #我是新增的,这边数字越大越好block_cipher = Nonea = Analysis(['main.py'], pathex=['C:\\Users\\*\\Documents\\GUI-20200323'], binaries=[], datas=[], hiddenimports=[], hookspath=[], runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False)
执行配置文件main.spec进行打包解决上个问题后我们输入下列代码来重新製作执行档,这次我们是要执行自订的配置文件.spec,PyInstaller会遵循.spec指定规範进行打包:
pyinstaller main.spec
6-1. 闪退问题以及如何查询原因(pkg_resources.py2_warn)
等了一会儿后终于跑完了:
113390 INFO: checking EXE113390 INFO: Building EXE because EXE-00.toc is non existent113391 INFO: Building EXE from EXE-00.toc113391 INFO: Appending archive to EXE C:\Users\*\Documents\GUI-20200323\build\main\main.exe113486 INFO: Building EXE from EXE-00.toc completed successfully.113501 INFO: checking COLLECT113502 INFO: Building COLLECT because COLLECT-00.toc is non existent113502 INFO: Building COLLECT COLLECT-00.toc184733 INFO: Building COLLECT COLLECT-00.toc completed successfully.
我们来看看main.exe是不是可以正常地打开吧,main.exe的位置在:
C:\Users\*\Documents\GUI-20200323\dist\main\main.exe
但是等等,为什么会闪退!!!原来打包成功并不等于.exe可以顺利执行呀。既然这样那我们改用终端机来开启.exe,这样就能知道程是闪退的原因了[1]:
(keras4) C:\Users\*\Documents\GUI-20200323>cd C:\Users\*\Documents\GUI-20200323\dist\main #切换路径到main.exe的位置(keras4) C:\Users\*\Documents\GUI-20200323\dist\main>main.exe #执行Traceback (most recent call last): File "site-packages\PyInstaller\loader\rthooks\pyi_rth_pkgres.py", line 13, in <module> File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 623, in exec_module exec(bytecode, module.__dict__) File "site-packages\pkg_resources\__init__.py", line 86, in <module>ModuleNotFoundError: No module named 'pkg_resources.py2_warn'# 这个是问题来源[15208] Failed to execute script pyi_rth_pkgres(keras4) C:\Users\*\Documents\GUI-20200323\dist\main>
原来是因为PyInstaller再打包过程中漏掉pkg_resources.py2_warn导致产生的.exe无法顺利执行。这时我们再次开启配置文件.spec,手动添加pkg_resources.py2_warn吧,记得再次执行main.spec前要先删掉build、dist两个资料夹[2][3][4]:
# -*- mode: python ; coding: utf-8 -*-import syssys.setrecursionlimit(9000000)block_cipher = Nonea = Analysis(['main.py'], pathex=['C:\\Users\\*\\Documents\\GUI-20200323'], binaries=[], datas=[], hiddenimports=['pkg_resources.py2_warn'], #我是新增的 hookspath=[], runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False)
pyinstaller main.spec
6-2. 闪退问题以及如何查询原因(sklearn.utils._cython_blas)
现在我们再次执行.exe,结果又闪退了...,没关係我们用上面讲的方法,透过终端机来执行.exe档就能知道问题了:
(keras4) C:\Users\*\Documents\GUI-20200323>cd C:\Users\*\Documents\GUI-20200323\dist\main #切换路径到main.exe的位置(keras4) C:\Users\*\Documents\GUI-20200323\dist\main>main.exe # 执行Traceback (most recent call last): File "main.py", line 3, in <module> File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 623, in exec_module exec(bytecode, module.__dict__) File "mylib.py", line 10, in <module> File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 623, in exec_module exec(bytecode, module.__dict__) File "site-packages\sklearn\linear_model\__init__.py", line 12, in <module> File "c:\users\*\appdata\local\continuum\anaconda3\envs\keras4\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 623, in exec_module exec(bytecode, module.__dict__) File "site-packages\sklearn\linear_model\_least_angle.py", line 22, in <module> File "sklearn\utils\arrayfuncs.pyx", line 1, in init sklearn.utils.arrayfuncsModuleNotFoundError: No module named 'sklearn.utils._cython_blas'# 这个是问题来源[11656] Failed to execute script main(keras4) C:\Users\*\Documents\GUI-20200323\dist\main>
这次是打包过程中漏掉sklearn.utils._cython_blas,PyInstaller你这个小淘气~:
# -*- mode: python ; coding: utf-8 -*-import syssys.setrecursionlimit(9000000)block_cipher = Nonea = Analysis(['main.py'], pathex=['C:\\Users\\*\\Documents\\GUI-20200323'], binaries=[], datas=[], hiddenimports=['pkg_resources.py2_warn', 'sklearn.utils._cython_blas'], # 再加1个 hookspath=[], runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False)
收工根据孟母三迁原理,我们终于顺利打包完成并且可以执行main.exe了(洒花)。然后你的萤幕会弹出辛苦拉的视窗以及一个黑色画面,消除黑色画面的方法很简单,只要依照下面代码位置方式修改.spec档后再次打包即可。

a = Analysis(['main.py'], pathex=['C:\\Users\\*\\Documents\\GUI-20200323'], binaries=[], datas=[], hiddenimports=['pkg_resources.py2_warn', 'sklearn.utils._cython_blas'], hookspath=[], runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False)pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)exe = EXE(pyz, a.scripts, [], exclude_binaries=True, name='main', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, console=False # console要从True改成False)
结论:
打包完成不等于可以顺利运行.exe档PyInstaller的打包方式是由.spec定义我们可以自定义.spec如果有引用第三方套件(Numpy、Pandas等等),容易有漏打包问题,导致执行档有闪退问题用终端机执行.exe来确认闪退原因每次自动打包前都要删掉资料夹build、资料夹dist、配置文件.spec,以确保遗毒消除每次手动打包前都要删掉资料夹build、资料夹dist,以确保遗毒消除补一下最后的main.spec代码,可以拿来跟下一篇比较# -*- mode: python ; coding: utf-8 -*-import sys # 这边要注意sys.setrecursionlimit(9000000) # 这边要注意block_cipher = Nonea = Analysis(['main.py'], pathex=['C:\\Users\\e10832\\Documents\\GUI-20200323'], binaries=[], datas=[], hiddenimports=['pkg_resources.py2_warn', 'sklearn.utils._cython_blas'], # 这边要注意 hookspath=[], runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False)pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)exe = EXE(pyz, a.scripts, [], exclude_binaries=True, name='main', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, console=True )# 命令视窗开启(True)coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, upx_exclude=[], name='main')
参考资料:
[1]https://blog.csdn.net/weixin_41417982/article/details/82216363
[2]https://blog.csdn.net/qq_40587575/article/details/86500445
[3]https://blog.csdn.net/j754379117/article/details/77281354
[4]https://medium.com/@peaceful0907/%E5%B0%87%E4%BD%A0%E7%9A%84python-code-%E6%89%93%E5%8C%85-pyinstaller-6777d0e06f58
[5]https://zhuanlan.zhihu.com/p/58199926
[6]https://zhuanlan.zhihu.com/p/40716095
[7]https://zhuanlan.zhihu.com/p/76974787
[8]https://xken831.pixnet.net/blog/post/463075799-%5Bpython%5D-%E8%A7%A3%E6%B1%BA-recursionerror%3A-maximum-recursion-depth-exce