当递归进行得很深入时,理解中的递归调用有什么特别之处?

塞弗特

我注意到在列表理解中使用递归时会发生一些奇怪的事情。如果递归太深,解释器似乎会变得空闲(我等了5分钟,什么也没发生)。

出于这个问题的考虑,假设我想展平嵌套列表(我不想-但这是一个简短的代码示例,它说明了我所遇到的问题):

def flatten(x):
    if isinstance(x, list):
        return [a for i in x for a in flatten(i)]
    else:
        return [x]

使用帮助函数创建嵌套列表:

def wrap_in_lists(value, depth):
    a = value
    for _ in range(depth):
        a = [a]
    return a

使用时效果很好:

>>> flatten(wrap_in_lists(1, 2**10))
[1]

但是当我使用它时,它完全停止了:

>>> flatten(wrap_in_lists(1, 2**11))
# Nothing happens, no exception, no result, no segfault, ...

我的问题是:这里发生了什么/发生了什么?为什么根本没有回应?


奇怪的是,使用生成器的类似方法没有显示此行为:

def flatten(l):
    def inner(x):
        for item in x:
            if isinstance(item, list):
                yield from inner(item)
            else:
                yield item
    return list(inner(l))

>>> flatten(wrap_in_lists(1, 2**11))
[1]

>>> # although increasing the depth leads to an recursion error
>>> flatten(wrap_in_lists(1, 2**12))
RecursionError: maximum recursion depth exceeded

如果重要的话,我会在Jupyter实验室的Windows上使用Python 64位3.6.6。

塞弗特

这是一个简单的StackOverflow,发生达到递归限制之前

在第二种方法(生成器)中,深度达到的递归极限2**12这意味着2**11第一种方法应该达到递归限制。这是因为列表综合会创建一个额外的堆栈框架,因此它是生成器解决方案的两倍。它不会引发RecursionError的事实意味着解释器发生了某些“致命”错误(或者某个地方存在无限循环)。

但是,这不是无限循环的,因为如果您检查jupyter实验室的响应(例如,如果从命令行启动jupyter lab),您会注意到在运行该flatten(wrap_in_lists(1, 2**11))后不久它将打印一个kernel <xyz> restarted因此,没有响应是不正确的,内核只是崩溃了,[*]在这种情况下在jupyter实验室单元中显示的只是意味着计算没有完成(由于崩溃)。

这就是为什么如果更改Python递归限制或使用为您更改了它的解释器时非常小心的原因之一

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章