What is the maximum recursion depth in Python, and how to increase it?
这里我有一个尾部递归函数:
1 2 3 4 5 6 7 8 | def fib(n, sum): if n < 1: return sum else: return fib(n-1, sum+n) c = 998 print(fib(c, 0)) |
它的计算结果是n=997,然后它就中断了,并发出了一个"超过比较中最大递归深度"
型
它是防止堆栈溢出的保护,是的。python(或者更确切地说,cpython实现)不优化尾部递归,而无限制的递归会导致堆栈溢出。您可以使用
python不是一种函数语言,tail递归不是一种特别有效的技术。如果可能,迭代地重写算法通常是一个更好的主意。
型
看起来你只需要设置一个更高的递归深度
1 | sys.setrecursionlimit(1500) |
型
这是为了避免堆栈溢出。python解释器限制递归的深度,以帮助您避免无限递归,从而导致堆栈溢出。尝试增加递归限制(sys.setrecursionlimit)或在不使用递归的情况下重新编写代码。
从python网站:
sys.getrecursionlimit() Return the current value of the recursion limit, the maximum depth of the Python interpreter stack. This limit prevents infinite recursion from causing an overflow of the C stack and crashing Python. It can be set by setrecursionlimit().
号
型
使用确保尾叫优化的语言。或者使用迭代。或者,和装饰师一起玩。
型
我意识到这是一个古老的问题,但是对于那些阅读,我建议不要使用递归来解决像这样的问题——列表更快,并且完全避免递归。我将按以下方式实施:
1 2 3 4 5 | def fibonacci(n): f = [0,1,1] for i in xrange(3,n): f.append(f[i-1] + f[i-2]) return 'The %.0fth fibonacci number is: %.0f' % (n,f[-1]) |
号
(如果从0而不是1开始计算斐波那契序列,请在xrange中使用n+1。)
型
当然,斐波那契数可以通过应用binet公式在o(n)中计算:
1 2 3 4 | from math import floor, sqrt def fib(n): return int(floor(((1+sqrt(5))**n-(1-sqrt(5))**n)/(2**n*sqrt(5))+0.5)) |
。
正如评论者所说,这不是O(1),而是O(n),因为
如果您经常需要更改递归限制(例如,在解决编程难题时),您可以这样定义一个简单的上下文管理器:
1 2 3 4 5 6 7 8 9 10 11 12 | import sys class recursionlimit: def __init__(self, limit): self.limit = limit self.old_limit = sys.getrecursionlimit() def __enter__(self): sys.setrecursionlimit(self.limit) def __exit__(self, type, value, tb): sys.setrecursionlimit(self.old_limit) |
然后,要调用具有自定义限制的函数,可以执行以下操作:
1 2 | with recursionlimit(1500): print(fib(1000, 0)) |
退出
型
还必须使用
Linux内核限制了进程的堆栈。
Python将局部变量存储在解释器的堆栈上,因此递归占用解释器的堆栈空间。
如果python解释器试图超过堆栈限制,Linux内核会出错。
堆栈限制大小由
python通过
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import resource import sys print resource.getrlimit(resource.RLIMIT_STACK) print sys.getrecursionlimit() # 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) |
。
当然,如果你继续增加ulimit,你的RAM将会耗尽,这将使你的计算机由于交换疯狂而停止,或者通过OOM杀手杀死python。
在bash中,您可以看到并设置堆栈限制(以KB为单位):
1 2 | ulimit -s ulimit -s 10000 |
我的默认值是8MB。
另请参见:
- 百万千克1在python脚本中设置stacksize百万千克1百万千克1python:Linux、Mac和Windows的硬递归限制是什么?百万千克1
型
在Ubuntu 16.10、python 2.7.12上测试。
型
我有一个类似的错误"超过了最大递归深度"。我发现错误是由我用os.walk循环访问的目录中的一个损坏文件触发的。如果您在解决此问题时遇到问题,并且正在处理文件路径,请确保缩小范围,因为它可能是一个损坏的文件。
型
如果只想得到几个斐波那契数,可以使用矩阵法。
1 2 3 4 | from numpy import matrix def fib(n): return (matrix('0 1; 1 1', dtype='object') ** n).item(1) |
。
它的速度和numpy使用快速求幂算法一样快。在O(登录N)中得到答案。它比binet公式更好,因为它只使用整数。但是如果你想要所有的斐波那契数都达到n,那么最好是通过记忆来实现。
型
使用发电机?
1 2 3 4 5 6 7 8 9 10 11 12 13 | def fib(): a, b = 0, 1 while True: yield a a, b = b, a + b fibs = fib() #seems to be the only way to get the following line to work is to #assign the infinite generator to a variable f = [fibs.next() for x in xrange(1001)] for num in f: print num |
上面的fib()函数改编自:http://intermediatepythonista.com/python-generators
型
许多人建议增加递归限制是一个很好的解决方案,但这并不是因为总是有限制。而是使用迭代解。
1 2 3 4 5 6 | def fib(n): a,b = 1,1 for i in range(n-1): a,b = b,a+b return a print fib(5) |
我想给你一个使用记忆法计算斐波那契的例子,因为这将允许你用递归法计算更大的数字:
1 2 3 4 5 6 7 8 9 10 11 12 | cache = {} def fib_dp(n): if n in cache: return cache[n] if n == 0: return 0 elif n == 1: return 1 else: value = fib_dp(n-1) + fib_dp(n-2) cache[n] = value return value print(fib_dp(998)) |
这仍然是递归的,但是使用了一个简单的哈希表,它允许重用以前计算的斐波那契数,而不是再次使用它们。
型
正如@alex建议的那样,您可以使用一个生成器函数来执行此操作。下面是您问题中的代码等价物:
1 2 3 4 5 6 7 8 9 10 11 | def fib(n): def fibseq(n): """ Iteratively return the first n Fibonacci numbers, starting from 0""" a, b = 0, 1 for _ in xrange(n): yield a a, b = b, a + b return sum(v for v in fibseq(n)) print format(fib(100000), ',d') # -> no recursion depth error |
。