为什么Python有最大递归深度限制?

7 浏览
0 Comments

为什么Python有最大递归深度限制?

Python对递归有最大递归深度的限制,但没有对迭代有最大深度的限制。为什么要限制递归?将递归视为迭代,并不限制递归调用次数,难道不更自然吗?

我只想说,这个问题的根源是尝试实现一个流(请参见此问题了解有关流的更多详细信息)。例如,假设我们想要编写一个生成自然数的流:

def stream_accum(s, n): # 将流强制转换为长度为n的列表
    def loop(s, acc):
        if len(acc) == n:
            return acc
        hd, tl = s()
        return loop(tl, acc + [hd])
    return loop(s, [])
def nats():
    def loop(n):
        return n, lambda: loop(n+1)
    return loop(1)

对于流的递归定义非常吸引人。然而,我认为更好/更符合Python风格的方法应该是使用生成器。

0
0 Comments

Python为什么有最大递归深度?

递归在调用栈上需要空间,而调用栈的大小是有限的。如果代码使用了太多层次的递归,就会出现所谓的堆栈溢出错误(也因为某个不知名的网站而变得著名)。Python似乎将这个限制(有点任意地)设定为大约1000层,但可以通过设置sys.setrecursionlimit来增加这个限制。

迭代使用类似于for循环的机制,通过增加某个计数器并有条件地将指令指针设置回循环的开头来实现。这在内存中是恒定的。

递归是一种在编程中常用的技术,它允许函数在其自身内部调用自身。虽然递归可以使代码更加简洁和可读,但过多的递归调用会导致一些问题。其中一个问题就是递归深度的限制。

递归深度是指递归函数调用自身的次数。每次函数调用都会在调用栈中创建一个新的帧,用于存储函数的局部变量和返回地址。当递归调用的层次太多时,调用栈会被耗尽,导致堆栈溢出错误。

Python为了防止这种情况的发生,限制了递归的最大深度。默认情况下,Python的最大递归深度约为1000层。当递归调用超过这个限制时,Python会引发RecursionError异常。

然而,有时候我们可能需要在某些特殊情况下增加递归深度的限制。幸运的是,Python提供了sys模块中的setrecursionlimit函数,可以用于设置递归的最大深度。通过调用sys.setrecursionlimit(n),我们可以将递归深度设置为n层。

需要注意的是,在增加递归深度的限制时,我们需要小心。过高的递归深度可能会导致栈溢出错误,从而导致程序崩溃。因此,我们应该根据实际情况和计算机的资源来决定适当的递归深度。

总结起来,Python有最大递归深度是因为递归调用需要使用调用栈的空间,而调用栈的大小是有限的。为了防止堆栈溢出错误,Python限制了递归的最大深度。如果需要增加递归深度的限制,可以使用sys.setrecursionlimit函数来实现。然而,需要小心不要设置过高的递归深度,以避免栈溢出错误。

0
0 Comments

为什么Python有最大递归深度?

Python有一个最大递归深度,这并不是Python独有的问题,它与每次调用在调用栈上占用空间以及栈的大小有关。仅仅进行迭代不会消耗栈空间,因此不受此限制。

并非每个递归调用都需要消耗栈空间。例如,某些语言可以自动将尾递归转化为迭代。然而,CPython选择不这样做(Python是否优化尾递归?)。

您可以通过调用sys.setrecursionlimit来增加Python调用栈的最大深度。

事实上,栈的大小并没有真正限制(除非堆有限制)。Python有意限制栈的大小。

所以,为了避免栈溢出错误,我们需要注意递归的使用,并确保递归深度不超过Python的最大限制。如果确实需要更深的递归深度,可以通过调用sys.setrecursionlimit来增加栈的大小。

以下是一个示例代码,展示如何使用sys.setrecursionlimit来增加Python调用栈的最大深度:

import sys
def recursive_function(n):
    if n <= 0:
        return
    recursive_function(n-1)
sys.setrecursionlimit(10000)
recursive_function(9999)

通过调用sys.setrecursionlimit(10000),我们将递归深度增加到了10000。但是需要注意的是,过度增加递归深度可能导致栈溢出错误或者程序运行变慢,因此需要谨慎使用。

0
0 Comments

为什么Python有最大递归深度?

首先,Python不会消除尾调用,这是一个问题。因此,很多在Scheme等语言中可以无限递归的函数,在Python中是有限制的。

其次,即使在支持尾调用消除的语言中,仍然有很多递归函数无法像迭代那样处理。例如,考虑一个简单的斐波那契函数,它会递归调用自己两次。

那么,为什么调用栈是有限资源呢?实际上,Python的栈帧理论上可以在堆上实现并链接在一起。在64位内存空间中,可以容纳比1000个栈帧更多的内容。事实上,即使是在几乎任何现代平台上的C栈也可以容纳比1000个递归Python解释器调用更多的内容。

部分原因是历史原因:Python解释器使用固定的C栈进行递归调用,而最初设计时针对的是32位(甚至24位或20位)平台,这些平台的C栈很小。

然而,这一点本可以改变,并且Python 3.0是一个完美的时机。那为什么没有改变呢?因为这是一种有意识的语言设计决策。在Pythonic代码中,递归通常是非常浅的(例如,像`os.walk`这样遍历浅树结构的代码)。如果你的函数递归深度接近1000,更可能是一个bug而不是有意为之。因此,限制保留下来。当然,这有点循环论证的感觉——如果移除了限制(尤其是如果消除了尾调用),那么更深的递归将变得更加符合惯例。但这也正是关键所在——Guido不希望深递归成为一种惯用法(大多数Python社区也持同样观点)。

需要注意的是:“您可以通过调用`sys.setrecursionlimit`来增加Python调用栈的最大深度。”

0