涉及递归调用的致命python错误

时间:2017-11-18 07:38:20

标签: python python-3.x recursion

python internals查询。请问大师请帮助我理解为什么下面的代码会导致“致命的python错误”,而不是很好地捕捉到递归限制溢出?

hasMany

用例如:

来称呼它
def flowfunc(x):
    try:
        if x < 0:
            flowfunc(x + 3)
            flowfunc(x + 5)
        else:
            flowfunc(x - 1)
    except:
        print("exception at: x = ", x)

所有突破损失

flowfunc(0)

似乎这一切都取决于第二次递归调用。以下代码表现良好:

exception at: x =  -1
Fatal Python error: Cannot recover from stack overflow.
...
...
[threads data...]

def flowfunc2(x):
    try:
        if x < 0:
            flowfunc2(x + 3)
            # flowfunc2(x + 5)
        else:
            flowfunc2(x - 1)
    except:
        print("exception at: x = ", x)

返回(值可能会根据可用的堆栈深度而改变):

flowfunc2(0)

我在python 3.6上。您的见解将受到赞赏。

2 个答案:

答案 0 :(得分:0)

两个片段之间的相似性:

在正面和负面之间有一个振荡的递归函数,从未真正终止。一旦达到Python设置的最大递归深度,就会捕获异常,打印当前值。

两个片段之间的区别:

在第一个版本中(你得到了致命的错误),在打印出最大深度达到异常后,而不是清理你的调用堆栈,你只需要升级一个并调用flowfunc(x + 5)堆积更多调用堆栈中的调用比Python可能处理的调用。那就是你得到致命错误的地方。在第二个版本中,在打印异常之后,您只需直接将None返回给原始调用者并终止程序的执行。在某种程度上,第二个代码段中的异常打印用作递归的base case,因为在调用者中没有其他任何操作,因此您的程序会正常终止。

所以是的,你的观察是正确的,它取决于第二次递归调用。

答案 1 :(得分:0)

这与https://bugs.python.org/issue6028的错误相同。

原因也在那里解释: “实际上,这是正常行为。但是,引发了RuntimeError 你在except子句中捕获它,然后无限地再次递归。 解释器意识到它“无法从堆栈溢出中恢复”, 正如消息所说,然后纾困。“

基本上,由于存在第二次递归调用,程序会在第一次错误被捕获后继续,并且它会保持分支并生成无限的RuntimeError。