这里有一个尾递归函数

def recursive_function(n, sum):
    if n < 1:
        return sum
    else:
        return recursive_function(n-1, sum+n)

c = 998
print(recursive_function(c, 0))

它一直工作到n=997,然后它就中断并抛出一个RecursionError:在比较中超过了最大递归深度。这只是一个堆栈溢出吗?有办法绕过它吗?


当前回答

资源。Setrlimit还必须用于增加堆栈大小和防止段故障

Linux内核限制了进程的堆栈。

Python将局部变量存储在解释器的堆栈上,因此递归占用解释器的堆栈空间。

如果Python解释器试图超过堆栈限制,Linux内核会使其出现分段错误。

堆栈限制大小由getrlimit和setrlimit系统调用控制。

Python通过资源模块提供了对这些系统调用的访问。

sys。例如,https://stackoverflow.com/a/3323013/895245中提到的setrecursionlimit只增加了Python解释器自身对其堆栈大小的限制,但它不会触及Linux内核对Python进程施加的限制。

示例程序:

main.py

import resource
import sys

print resource.getrlimit(resource.RLIMIT_STACK)
print sys.getrecursionlimit()
print

# Will segfault without this line.
resource.setrlimit(resource.RLIMIT_STACK, [0x10000000, resource.RLIM_INFINITY])
sys.setrecursionlimit(0x100000)

def f(i):
    print i
    sys.stdout.flush()
    f(i + 1)
f(0)

当然,如果你继续增加setrlimit,你的RAM最终会用完,这将使你的计算机由于疯狂的交换而变慢到停止,或者通过OOM杀手杀死Python。

在bash中,您可以使用以下命令查看并设置堆栈限制(单位为kb):

ulimit -s
ulimit -s 10000

我的默认值是8Mb。

参见:

在python脚本中设置stacksize Linux、Mac和Windows的硬递归限制是什么?

在Ubuntu 16.10, Python 2.7.12上测试。

其他回答

如果你经常需要改变递归限制(例如在解决编程难题时),你可以定义一个简单的上下文管理器,像这样:

import sys

class recursionlimit:
    def __init__(self, limit):
        self.limit = limit

    def __enter__(self):
        self.old_limit = sys.getrecursionlimit()
        sys.setrecursionlimit(self.limit)

    def __exit__(self, type, value, tb):
        sys.setrecursionlimit(self.old_limit)

然后调用具有自定义限制的函数,您可以这样做:

with recursionlimit(1500):
    print(fib(1000, 0))

从with语句体退出时,递归限制将恢复到默认值。

附注:您可能还想增加Python进程的堆栈大小,以获得较大的递归限制值。例如,这可以通过ulimit shell内置或limits.conf(5)文件来完成。

是的,它是防止堆栈溢出的一种方法。Python(或者更确切地说,CPython实现)没有优化尾部递归,并且无限制的递归会导致堆栈溢出。你可以用sys.getrecursionlimit检查递归限制:

import sys
print(sys.getrecursionlimit())

并使用sys.setrecursionlimit更改递归限制:

sys.setrecursionlimit(1500)

但这样做是危险的——标准限制有点保守,但Python的堆栈框架可能相当大。

Python不是函数式语言,尾递归也不是一种特别有效的技术。如果可能的话,迭代地重写算法通常是一个更好的主意。

资源。Setrlimit还必须用于增加堆栈大小和防止段故障

Linux内核限制了进程的堆栈。

Python将局部变量存储在解释器的堆栈上,因此递归占用解释器的堆栈空间。

如果Python解释器试图超过堆栈限制,Linux内核会使其出现分段错误。

堆栈限制大小由getrlimit和setrlimit系统调用控制。

Python通过资源模块提供了对这些系统调用的访问。

sys。例如,https://stackoverflow.com/a/3323013/895245中提到的setrecursionlimit只增加了Python解释器自身对其堆栈大小的限制,但它不会触及Linux内核对Python进程施加的限制。

示例程序:

main.py

import resource
import sys

print resource.getrlimit(resource.RLIMIT_STACK)
print sys.getrecursionlimit()
print

# Will segfault without this line.
resource.setrlimit(resource.RLIMIT_STACK, [0x10000000, resource.RLIM_INFINITY])
sys.setrecursionlimit(0x100000)

def f(i):
    print i
    sys.stdout.flush()
    f(i + 1)
f(0)

当然,如果你继续增加setrlimit,你的RAM最终会用完,这将使你的计算机由于疯狂的交换而变慢到停止,或者通过OOM杀手杀死Python。

在bash中,您可以使用以下命令查看并设置堆栈限制(单位为kb):

ulimit -s
ulimit -s 10000

我的默认值是8Mb。

参见:

在python脚本中设置stacksize Linux、Mac和Windows的硬递归限制是什么?

在Ubuntu 16.10, Python 2.7.12上测试。

我不确定我是不是在重复某人的意思但前段时间有人写了一个y算子用于递归调用函数

def tail_recursive(func):
  y_operator = (lambda f: (lambda y: y(y))(lambda x: f(lambda *args: lambda: x(x)(*args))))(func)
  def wrap_func_tail(*args):
    out = y_operator(*args)
    while callable(out): out = out()
    return out
  return wrap_func_tail

然后递归函数需要形式:

def my_recursive_func(g):
  def wrapped(some_arg, acc):
    if <condition>: return acc
    return g(some_arg, acc)
  return wrapped

# and finally you call it in code

(tail_recursive(my_recursive_func))(some_arg, acc)

对于斐波那契数,你的函数是这样的:

def fib(g):
  def wrapped(n_1, n_2, n):
    if n == 0: return n_1
    return g(n_2, n_1 + n_2, n-1)
  return wrapped

print((tail_recursive(fib))(0, 1, 1000000))

输出:

..684684301719893411568996526838242546875

(实际上是数字的音调)

RecursionError:在比较中超出的最大递归深度

解决方案:

首先,最好知道当你在一个大输入(> 10^4)上用Python执行递归函数时,你可能会遇到“最大递归深度超出错误”。

Python中的sys模块有一个函数getrecursionlimit()可以显示Python版本中的递归限制。

import sys
print("Python Recursive Limitation = ", sys.getrecursionlimit())

在某些版本的Python中,默认值是1000,而在另一些版本中则是1500

你可以改变这个限制,但重要的是要知道,如果你增加太多,就会出现内存溢出错误。

所以在增加它之前要小心。你可以使用setrecursionlimit()在Python中增加这个限制。

import sys
sys.setrecursionlimit(3000)

请点击此链接了解导致此问题的更多信息:

https://elvand.com/quick-sort-binary-search/