kivy 中超出了最大递归深度,但仅在打包时超出,而不是在使用 python 开发应用程序时

Posted

技术标签:

【中文标题】kivy 中超出了最大递归深度,但仅在打包时超出,而不是在使用 python 开发应用程序时【英文标题】:Maximum recursion depth exceeded in kivy but only when packaging, not when developing the app in python 【发布时间】:2019-06-25 13:50:54 【问题描述】:

我正在尝试打包一个需要多个导入的应用程序,其中包括 matplotlib.pyplot

kivy 应用程序(经过简化,但仍在运行)是:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
import matplotlib.pyplot


Builder.load_string("""
<MyWidget>:
    id: my_widget
    FileChooserIconView:
        id: filechooser
        on_selection: my_widget.selected(filechooser.selection)
    Image:
        id: image
        source: ""
""")


class MyWidget(BoxLayout):

    def selected(self,filename):
        self.ids.image.source = filename[0]


class MyApp(App):
    def build(self):
        return MyWidget()


if __name__ == '__main__':
    MyApp().run()

这个应用程序使用 spyder 在 python 中完美运行。

但是,当我尝试将其打包为一个独立的 kivy 应用程序时,它给了我错误,超出了最大递归深度。

我很惊讶,不知道问题出在哪里,因为:

1.应用中没有递归函数。

2.在 python spyder 开发和测试时完美运行,唯一的问题是在打包过程中。

3.我尝试了多个选项,包括注释掉几个部分,最令人惊讶的是,当我注释掉导入 matplotlib.pyplot 时,应用程序包很好。但是我需要这个应用程序的 matplotlib.pyplot,所以不能把它拿出来。

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
#import matplotlib.pyplot


Builder.load_string("""
<MyWidget>:
    id: my_widget
    FileChooserIconView:
        id: filechooser
        on_selection: my_widget.selected(filechooser.selection)
    Image:
        id: image
        source: ""
""")


class MyWidget(BoxLayout):

    def selected(self,filename):
        self.ids.image.source = filename[0]


class MyApp(App):
    def build(self):
        return MyWidget()


if __name__ == '__main__':
    MyApp().run()

以上代码运行良好,打包良好。

可以导入到 kivy 应用程序的文件大小是否有限制?我已经尝试使用 sys.setrecursionlimit(high numbers) 来增加递归限制,但这不是解决这个问题的方法。 我真的迷路了。任何见解表示赞赏。

谢谢

2019 年 2 月 4 日编辑: 有人建议这个问题:pyinstaller creating EXE RuntimeError: maximum recursion depth exceeded while calling a Python object 是重复的并回答了这个问题。虽然这绝对是一个相关的问题并且很有帮助,但我的错误发生在创建 kivy 包的第一阶段: python -m PyInstaller --name touchtracer examples-path\demo\touchtracer\main.py

【问题讨论】:

你用什么打包app? 我正在遵循 Windows 的 kivy 打包说明kivy.org/doc/stable/guide/packaging-windows.html 我正在遵循 Windows kivy.org/doc/stable/guide/packaging-windows.html 的 kivy 打包说明,我在 anaconda 环境中使用 Windows 7、python 3.6。打包像往常一样开始,它为 dist 和 build 创建规范文件和空文件夹。在某些时候,在“处理前安全导入 ....six.moves”的行周围,它比平时停留了更长的时间,然后突然非常迅速地转到 File:.. 的几行,用于不同的文件,最后超出最大递归深度。我不知道发生了什么或如何处理它。谢谢 pyinstaller creating EXE RuntimeError: maximum recursion depth exceeded while calling a Python object的可能重复 虽然约翰安德森提出的问题(感谢链接)在规范文件的开头有一个答案:import sys sys.setrecursionlimit(5000),但它不起作用,因为我的问题发生在创建 kivy 包的第一阶段:python -m PyInstaller --name touchtracer examples-path\demo\touchtracer\main.py 这一步会覆盖我在规范文件上写的任何内容。 【参考方案1】:

非常感谢所有试图提供帮助的人。 我找到了答案,我希望它可以帮助其他尝试创建 kivy 包并且导入 python 模块时出现问题的人。

一旦您准备好打包您的 main.py 脚本:

1.从说明开始

https://kivy.org/doc/stable/guide/packaging-windows.html

然后做第一步:

python -m PyInstaller --name touchtracer examples-path\demo\touchtracer\main.py

这会给你maximum recursion depth exceeded 的错误或者它最初给你的任何错误。不用担心。此步骤的目的是创建一个初始的spec 文件。

2.打开spec文件并添加kivy指令给你的所有额外内容

https://kivy.org/doc/stable/guide/packaging-windows.html

即:

from kivy.deps import sdl2, glew
Tree('examples-path\\demo\\touchtracer\\'),
*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],

3.除此之外,在规范文件的开头添加以下内容:

import sys
sys.setrecursionlimit(5000) # (or some big number)

4. 还可以在您可能需要的隐藏导入中添加任何导入。

hiddenimports=[] # change to (example importing pandas and matplotlib) hiddenimports=['pandas', 'matplotlib']

5.只需按照

的最后一步
https://kivy.org/doc/stable/guide/packaging-windows.html

即:

python -m PyInstaller touchtracer.spec

并构建您的应用

【讨论】:

【参考方案2】:

当我们进入递归时,存在堆栈溢出的风险,并且在底层工作的 Cpython 不会自行优化尾递归,所以如果你走得太深,你会更接近堆栈溢出.通常不同的 Cpython/python 风格具有不同的递归许可深度,您在本地运行的 python 版本具有更宽松的深度限制(通常是因为假设开发人员有足够好的计算机来实现这一点)。但是,当您使用工具打包应用程序时,它们通常会将sys.setrecursionlimit 覆盖为更保守的值,因为它们会尝试确保您不会在硬件较低的系统上导致堆栈溢出。

遗憾的是,这个问题没有灵丹妙药,您可以尝试查看您的特定经理并更改限制(不推荐),或者您可以尝试将递归块转换为迭代块。

【讨论】:

感谢您的回答 anand_v.singh。但是,应该有一些解决方案,对吧?不可能在kivy中不能使用matplotlib.pyplot这样的通用模块。我的代码没有任何递归块,这使得它更加令人惊讶,因为我试图在问题的第 1 点中解释。 @Ivan 尝试更改 sys.setrecursionlimit 标志,您将不得不搜索如何为 kivy 准确地做到这一点,但可以做到。

以上是关于kivy 中超出了最大递归深度,但仅在打包时超出,而不是在使用 python 开发应用程序时的主要内容,如果未能解决你的问题,请参考以下文章

Python - RecursionError:比较错误中超出了最大递归深度[重复]

RecursionError:比较中超出了最大递归深度'

如何在反应中超过最大更新深度

递归过多/超出最大调用堆栈大小(Jquery 1.9.1)

Python:打印自定义异常时超出最大递归深度

RecursionError:重命名列条目后调用 Python 对象时超出最大递归深度