递归错误:在比较中超过最大递归深度。

18

我希望这不是一个重复的问题,如果是,我很抱歉,但我已经在谷歌和Stack Overflow上查找过了,目前还没有发现什么...

最小完整可工作示例

我知道如果一个函数不断地调用自己,那么这个过程就不能无限制地进行下去,否则会出现堆栈溢出,因此在达到一定限制后会引发错误。例如:

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

问题

在上述错误中,“in comparison”是指什么?我的问题是这两种情况之间有何区别,导致出现了两个不同的错误。


递归深度约为1000,因此该值过大。 - Willem Van Onsem
只是猜测:比较是 n==0,错误信息告诉我们这是一种条件递归。 - PM 2Ring
2
这意味着在比较 n == 0 中发生了堆栈溢出。这有什么大不了的? - Aran-Fey
3个回答

11

当抛出RecursionError时,Python解释器可能会为您提供导致错误的调用上下文。这仅用于调试,以给您提示在代码中应该查找哪些位置来修复问题。

例如,看看导致不同消息的循环str调用设置:

>>> 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的问题讨论(链接)中,没有关于此行为的文档记录,但您可以搜索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

顺便说一下,如果您有1000个缩进级别,您会得到一个“IndentationError:too many levels of indentation”错误:p - Arne
5
当存在太多函数调用时,会触发RecursionError异常,而不是只有在存在循环时才会发生。n == 0将调用一个函数(__eq__),并且该函数导致程序达到了栈的限制。Python检测到这一情况,并打印出相关的错误信息。 - Aran-Fey
@aran-fey 这也有一定道理。那么你是在说我得到的错误是Python在函数__eq__中报告递归错误的方式吗? - tim-mccurrach
我曾经看到过一个简单的打印函数出现了相同的错误,有人能够复现吗?def print_path(path): print("In Python") print("Path:"+ path) print("Out Python") return True if __name__ == '__main__': message = "Hey D" print_path(message) - DTK
1
@DTK 不行,我不能:https://replit.com/@a-recknagel/AdmiredChocolateIntercept#main.py,一定有其他代码正在执行导致它出错。 - Arne
显示剩余8条评论

7

我试着使用它并发现了一些有趣的结果。

正如我们所知:

def foo():
    foo()

Gives rise to

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在错误信息方面只能提供有限的帮助。


0

我的代码出现了类似的RecursionError问题,具体错误如下:

File "C:\Users\xx\AppData\Local\Programs\Python\Python37-32\lib\site-packages\matplotlib\backends\_backend_tk.py", line 473, in flush_events
self._master.update()
.
.
.

File "C:\Users\xxx\AppData\Local\Programs\Python\Python37-32\lib\abc.py", line 139, in __instancecheck__
return _abc_instancecheck(cls, instance)
RecursionError: maximum recursion depth exceeded in comparison

在下面的代码中删除了self.canvas.flush_events()行后,问题得到解决。
def update(self, k=1, step = 1):

    if self.start.get() and not self.is_paused.get(): 
        idx = [i for i in range(0,k,1)][-1]
        x_data.append(idx)
        y_data.append(np.sin(idx/5))
        self.line.set_data(x_data, y_data)
        self.fig.gca().relim()
        self.fig.gca().autoscale_view()
        self.canvas.draw()
        #self.canvas.flush_events()
        k += step
         
    if k <= self.voltage_range.get():
        
        self.after(100, self.update, k)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接