使用py2app打包Python应用遇RecursionError,求解决方法
Python应用打包RecursionError问题解决及可行方案
问题描述
使用python setup.py py2app(非开发模式)打包Python应用时触发RecursionError,日志显示编译sympy/polys/polyquinticconst.py时递归溢出;代码中使用了scipy.interpolate.lagrange做插值,测试发现:
- 用
python setup.py py2app -A(开发模式)打包正常,但无法在其他电脑运行; - 修改
np.set_printoptions(precision)的数值会再次触发错误。
问题分析
日志里的错误是py2app在扫描该文件字节码时出现的递归溢出,并非代码运行时的错误,但会导致打包过程中断或不完整。原因在于scipy.interpolate.lagrange底层依赖sympy库,打包时会自动引入sympy的模块,而polyquinticconst.py包含深度递归的代码逻辑,py2app的字节码扫描器无法处理这种递归深度。
解决步骤
1. 跳过指定文件的字节码编译
在setup.py中配置py2app,直接跳过polyquinticconst.py的编码处理,避免触发递归错误:
from setuptools import setup APP = ['你的主脚本文件名.py'] OPTIONS = { 'py2app': { 'skip_encoding': ['sympy/polys/polyquinticconst.py'], } } setup( app=APP, options=OPTIONS, setup_requires=['py2app'], )
2. 替换依赖模块(从根源避免问题)
如果你的场景只需要拉格朗日插值功能,可以用纯numpy实现替代scipy.interpolate.lagrange,这样打包时就不会引入sympy库:
import numpy as np def lagrange_interp(xdata, ydata): n = len(xdata) poly = np.poly1d([0.0]) for i in range(n): # 构造第i个基多项式 li = np.poly1d([1.0]) for j in range(n): if i != j: li *= np.poly1d([1/(xdata[i]-xdata[j]), -xdata[j]/(xdata[i]-xdata[j])]) poly += ydata[i] * li return poly # 替换原代码中的poly = interpolate.lagrange(xdata, ydata) poly = lagrange_interp(xdata, ydata)
3. 临时调大递归深度(不推荐)
在打包脚本开头增加递归限制,仅作为临时应急方案,可能引发其他未知问题:
import sys sys.setrecursionlimit(10000) # 调大递归深度阈值
可行的替代打包方案
如果py2app的问题难以彻底解决,可以尝试以下工具:
- PyInstaller:跨平台打包工具,对科学计算库支持较好,命令简单:
macOS下打包后可能需要处理代码签名,确保跨机器运行时不会被系统拦截。# 命令行程序用--console,GUI程序用--windowed pyinstaller --onefile --console your_script.py - Nuitka:将Python代码编译为C代码再打包,运行效率更高,对复杂依赖的处理更稳定:
打包后的程序体积更小,运行速度更快,适合性能要求较高的场景。# 打包为macOS应用 bundle nuitka --standalone --macos-create-app-bundle your_script.py
内容的提问来源于stack exchange,提问作者Xavier
相关产品推荐
相关产品推荐

