RecursionError:比较超过最大递归深度

Posted

技术标签:

【中文标题】RecursionError:比较超过最大递归深度【英文标题】:RecursionError: maximum recursion depth exceeded in comparison 【发布时间】:2019-03-23 04:57:30 【问题描述】:

我希望这不是重复的,如果是这样,我深表歉意,但是已经进行了一些谷歌搜索并查看了堆栈溢出,但还没有找到任何东西......

MCVE

我知道如果一个函数不断地调用自己,这不可能在没有堆栈溢出的情况下无限期地发生,因此在一定限制后会引发错误。例如:

def foo():
    return foo()

foo()

这会导致以下错误:

RecursionError: maximum recursion depth exceeded

但是,如果我编写如下函数:

def count(n):
    if n == 0:
        return 0
    else:
        return count(n-1)+1

count(1000)

我得到一个稍微不同的错误:

RecursionError: maximum recursion depth exceeded in comparison

问题

上述错误中的“比较”指的是什么。我想我要问的是这两种情况有什么区别,这会导致两种不同的错误。

【问题讨论】:

递归深度在1000左右,所以值太大了。 只是猜测:比较的是n==0,错误信息告诉我们这是一个条件递归。 表示比较n == 0时发生了堆栈溢出。有什么大不了的? 【参考方案1】:

当出现RecursionError 时,python 解释器还可能会为您提供导致错误的调用的上下文。这仅用于调试,提示您应该在代码中的哪个位置查找以解决问题。

例如,请参阅此循环 str-call setup,它会导致不同的消息:

>>> class A:
...     def __str__(self):
...         return str(self.parent)
>>> a = A()
>>> a.parent = a
>>> str(a)
RecursionError: maximum recursion depth exceeded while calling a Python object

在引入RecursionError 的the issue discussion 上没有此行为的文档,但您可以搜索cpython 代码以查找Py_EnterRecursiveCall 的出现。然后您可以看到将根据引发错误的位置返回的实际上下文:

Py_EnterRecursiveCall(" while encoding a JSON object")
Py_EnterRecursiveCall(" while pickling an object")
Py_EnterRecursiveCall(" in __instancecheck__")
Py_EnterRecursiveCall(" in __subclasscheck__")
Py_EnterRecursiveCall(" in comparison")
Py_EnterRecursiveCall(" while getting the repr of an object")
Py_EnterRecursiveCall(" while getting the str of an object")
Py_EnterRecursiveCall(" while calling a Python object")
Py_EnterRecursiveCall("while processing _as_parameter_") # sic
# .. and some more that I might have missed

【讨论】:

感谢您提供如此全面的回答。我认为我对实际递归深度的概念可能不正确?澄清一下: if 语句会增加递归深度吗?例如 1000 个嵌套的 if 语句会引发类似的错误吗? 不,RecursionErrors 仅在解释器找到循环时发生,这意味着同一个函数被无限调用。 好的。谢谢你。我想我很困惑为什么RecursionError 出现在比较中。如果在比较之前我的函数中有其他行,我仍然会收到错误in comparison。与之前的其他行相比,它有什么特别之处?为什么函数调用次数过多时没有出现错误? python 可以为您提供的关于错误发生位置的提示数量有限。实现递归错误的人决定如果它发生在包含比较的 if-else 块中,则将其打印为上下文 存在循环时引发 RecursionError 是不正确的。当堆栈上的函数调用过多时,会引发 RecursionError。 n == 0 调用一个函数 (__eq__),该函数导致您的程序达到堆栈限制。 Python 检测到这一点,并打印一条信息性错误消息。【参考方案2】:

我尝试了一下,发现了一些有趣的结果。

据我们所知:

def foo():
    foo()

引起

RecursionError: maximum recursion depth exceeded

我发现的是

def bar():
    if False:
        return 0
    else:
        bar()

def baz():
    if True:
        baz()
    else:
        return 0

bar()baz() 都会产生

RecursionError: maximum recursion depth exceeded

然后

def ding():
    if 1 == 2:
        return 0
    else:
        ding()

def dong():
    if 1 != 2:
        dong()
    else:
        return 0

ding()dong() 都会产生

RecursionError: maximum recursion depth exceeded in comparison

我的直觉是,python 知道您正在使用比较器 =,!,<,> 进行比较,并且这种比较永远不会达到“基本情况”条件(在最大深度的范围内)。所以 python 让你知道你的比较永远不会收敛到满足条件。

当您尝试时,这种帮助开始失效

def oops():
    if 1 == 2:
        oops()
    else:
        oops()

但最终python只能对错误消息有帮助。

【讨论】:

以上是关于RecursionError:比较超过最大递归深度的主要内容,如果未能解决你的问题,请参考以下文章

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

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

RecursionError:超出最大递归深度

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

Pyinstaller RecursionError:超出最大递归深度

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