Python中的最大recursion深度是多less,以及如何增加?
我有这个尾recursion函数:
def fib(n, sum): if n < 1: return sum else: return fib(n-1, sum+n) c = 998 print(fib(c, 0))
它工作到n = 997,然后它只是打破和吐出“比较RuntimeError
超过最大recursion深度”。 这只是一个堆栈溢出? 有没有办法避开它?
这是一个防止堆栈溢出,是的。 Python(或更确切地说,CPython实现)不会优化尾recursion,而无约束的recursion会导致堆栈溢出。 您可以使用sys.setrecursionlimit
来更改recursion限制,但这样做是危险的 – 标准限制稍微保守,但是Python堆栈框架可能相当大。
Python不是一种function语言,尾recursion不是一个特别有效的技术。 如果可能的话,迭代地重写algorithm通常是更好的主意。
看起来你只需要设置一个更高的recursion深度
sys.setrecursionlimit(1500)
这是为了避免堆栈溢出。 Python解释器限制recursion的深度,以帮助您避免无限recursion,导致堆栈溢出。 尝试增加recursion限制(sys.setrecursionlimit)或不recursion地重写代码。
来自python网站 :
sys.getrecursionlimit()
返回recursion限制的当前值,即Python解释器堆栈的最大深度。 此限制可以防止无限recursion导致C堆栈溢出并导致Python崩溃。 它可以通过setrecursionlimit()来设置。
使用保证尾部呼叫优化的语言。 或者使用迭代。 或者, 装饰者可爱。
我意识到这是一个老问题,但对于那些阅读,我会build议不要使用recursion来解决这个问题 – 列表要快得多,并且完全避免recursion。 我将这个实现为:
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开始计算斐波那契数列,则使用xrange中的n + 1)
我遇到了类似的问题,错误“超过最大recursion深度”。 我发现这个错误是由我用os.walk循环的目录中的一个损坏的文件触发的。 如果您在解决此问题时遇到问题,并且正在处理文件path,请确保将其缩小,因为它可能是损坏的文件。
当然可以通过应用Binet公式来计算O(1)中的斐波那契数:
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))
当结果不再适合长时,你将需要从numpy的大整数。
使用发电机?
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
还必须使用resource.setrlimit
来增加堆栈大小并防止段错误
Linux内核限制了进程的堆栈。
Python将局部variables存储在解释器的堆栈中,因此recursion会占用解释器的堆栈空间。
如果Python解释器试图超出堆栈限制,则Linux内核会对其进行段错误检测。
堆栈限制大小由getrlimit
和setrlimit
系统调用进行控制。
Python通过resource
模块提供对这些系统调用的访问。
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)
当然,如果你不断增加ulimit,你的RAM就会耗尽,这会使你的电脑因为交换的疯狂而停下来,或者通过OOM Killer来杀死Python。
从bash中,您可以看到并设置堆栈限制(kb):
ulimit -s ulimit -s 10000
我的默认值是8Mb。
也可以看看:
- 在python脚本中设置stacksize
- Python:什么是Linux,Mac和Windows的硬recursion限制?
在Ubuntu 16.10,Python 2.7.12上testing
许多人build议增加recursion限制是一个很好的解决scheme,但不是因为总会有限制。 而是使用迭代解决scheme。
def fib(n): a,b = 1,1 for i in range(n-1): a,b = b,a+b return a print fib(5)
正如@alex build议的那样 ,你可以使用一个生成器函数来执行此操作。 下面是你问题中代码的等价物:
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