Python中的最大递归深度是多少,以及如何增加它?

Python中的最大递归深度是多少,以及如何增加它?,python,recursion,Python,Recursion,我这里有一个尾部递归函数: 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)) def递归函数(n,和): 如果n

我这里有一个尾部递归函数:

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))
def递归函数(n,和):
如果n<1:
回报金额
其他:
返回递归函数(n-1,和+n)
c=998
打印(递归函数(c,0))

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

看起来你只需要:


这是为了避免堆栈溢出。Python解释器限制递归的深度,以帮助您避免无限递归,从而导致堆栈溢出。 尝试增加递归限制(
sys.setrecursionlimit
)或在没有递归的情况下重新编写代码

从:

sys.getrecursionlimit()

返回递归限制的当前值,即Python解释器堆栈的最大深度。这个限制可以防止无限递归导致C堆栈溢出和Python崩溃。它可以设置为


是的,它可以防止堆栈溢出。Python(或者更确切地说,是CPython实现)没有优化尾部递归,不受约束的递归会导致堆栈溢出。您可以使用以下方法检查递归限制:

并使用以下命令更改递归限制:

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


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

使用保证尾部调用优化的语言。或者使用迭代。另一种选择是,要聪明点。

我意识到这是一个老问题,但对于那些阅读的人来说,我建议不要使用递归来解决这样的问题-列表要快得多,并且完全避免递归。我会实施以下措施:

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。)

我遇到了类似的问题,错误是“超过了最大递归深度”。我发现该错误是由我使用
os.walk
循环的目录中的损坏文件触发的。如果您在解决此问题时遇到问题,并且正在使用文件路径,请确保缩小范围,因为它可能是一个损坏的文件

编辑:6年后,我意识到我的“使用生成器”是轻率的,没有回答这个问题。我道歉

我想我的第一个问题是:你真的需要改变递归限制吗?如果不是,那么可能我的答案或其他任何不涉及更改递归限制的答案都将适用。否则,如前所述,使用
sys.getrecursionlimit(n)
覆盖递归限制

使用发电机

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()
函数改编自。

当然,斐波那契数可以通过应用以下公式以O(n)为单位计算:


正如评论者所指出的,这不是O(1),而是O(n),因为
2**n
。另一个区别是,您只得到一个值,而使用递归,您得到的所有值都是该值。

许多人建议增加递归限制是一个好的解决方案,但这不是因为总是有限制。相反,使用迭代解决方案

def fib(n):
    a,b = 1,1
    for i in range(n-1):
        a,b = b,a+b
    return a
print fib(5)
作为@alex,您可以使用a按顺序而不是递归地执行此操作

下面是您问题中代码的等价物:

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

资源。setrlimit
还必须用于增加堆栈大小和防止segfault

Linux内核

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

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

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

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

sys.setrecursionlimit
例如,at仅增加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最终将耗尽,这将使您的计算机因交换疯狂而停止运行,或者通过

在bash中,您可以通过以下方式查看和设置堆栈限制(以kb为单位):

我的默认值是8Mb

另见:


在Ubuntu16.10、Python2.7.12上测试。

如果您只想得到几个斐波那契数,可以使用矩阵方法

from numpy import matrix

def fib(n):
    return (matrix('0 1; 1 1', dtype='object') ** n).item(1)

它的速度很快,因为numpy使用快速求幂算法。在O(logn)中得到答案。它比比奈公式好,因为它只使用整数。但是,如果您希望所有斐波那契数都达到n,那么最好通过记忆来实现。

如果您经常需要更改递归限制(例如,在解决编程难题时),您可以定义一个简单的方法,如下所示:

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)
然后,要调用具有自定义限制的函数,可以执行以下操作:

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

退出带有语句的
主体时,递归限制将恢复为默认值。

我想给您一个使用记忆来计算斐波那契的示例,因为这将允许您使用递归计算更大的数:

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))
这仍然是递归的,但使用了一个简单的哈希表,允许重用以前计算的斐波那契数,而不是重复使用。

import sys
系统设置递归限制(1500)
def fib(n,总和):
如果n<1:
回报金额
其他:
返回fib(n-1,和+n)
c=998
打印(fib(c,0))

我们可以使用
@lru\u cache
decorator和
setrecurs来实现这一点
ulimit -s
ulimit -s 10000
from numpy import matrix

def fib(n):
    return (matrix('0 1; 1 1', dtype='object') ** n).item(1)
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)
with recursionlimit(1500):
    print(fib(1000, 0))
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))
import sys
from functools import lru_cache

sys.setrecursionlimit(15000)


@lru_cache(128)
def fib(n: int) -> int:
    if n == 0:
        return 0
    if n == 1:
        return 1

    return fib(n - 2) + fib(n - 1)


print(fib(14000))
3002468761178461090995494179715025648692747937490792943468375429502230242942284835863402333575216217865811638730389352239181342307756720414619391217798542575996541081060501905302157019002614964717310808809478675602711440361241500732699145834377856326394037071666274321657305320804055307021019793251762830816701587386994888032362232198219843549865275880699612359275125243457132496772854886508703396643365042454333009802006384286859581649296390803003232654898464561589234445139863242606285711591746222880807391057211912655818499798720987302540712067959840802106849776547522247429904618357394771725653253559346195282601285019169360207355179223814857106405285007997547692546378757062999581657867188420995770650565521377874333085963123444258953052751461206977615079511435862879678439081175536265576977106865074099512897235100538241196445815568291377846656352979228098911566675956525644182645608178603837172227838896725425605719942300037650526231486881066037397866942013838296769284745527778439272995067231492069369130289154753132313883294398593507873555667211005422003204156154859031529462152953119957597195735953686798871131148255050140450845034240095305094449911578598539658855704158240221809528010179414493499583473568873253067921639513996596738275817909624857593693291980841303291145613566466575233283651420134915764961372875933822262953420444548349180436583183291944875599477240814774580187144637965487250578134990402443365677985388481961492444981994523034245619781853365476552719460960795929666883665704293897310201276011658074359194189359660792496027472226428571547971602259808697441435358578480589837766911684200275636889192254762678512597000452676191374475932796663842865744658264924913771676415404179920096074751516422872997665425047457428327276230059296132722787915300105002019006293320082955378715908263653377755031155794063450515731009402407584683132870206376994025920790298591144213659942668622062191441346200098342943955169522532574271644954360217472458521489671859465232568419404182043966092211744372699797375966048010775453444600153524772238401414789562651410289808994960533132759532092895779406940925252906166612153699850759933762897947175972147868784008320247586210378556711332739463277940255289047962323306946068381887446046387745247925675240182981190836264964640612069909458682443392729946084099312047752966806439331403663934969942958022237945205992581178803606156982034385347182766573351768749665172549908638337611953199808161937885366709285043276595726484068138091188914698151703122773726725261370542355162118164302728812259192476428938730724109825922331973256105091200551566581350508061922762910078528219869913214146575557249199263634241165352226570749618907050553115468306669184485910269806225894530809823102279231750061652042560772530576713148647858705369649642907780603247428680176236527220826640665659902650188140474762163503557640566711903907798932853656216227739411210513756695569391593763704981001125
def fib_bottom_up(n):

    bottom_up = [None] * (n+1)
    bottom_up[0] = 1
    bottom_up[1] = 1

    for i in range(2, n+1):
        bottom_up[i] = bottom_up[i-1] + bottom_up[i-2]

    return bottom_up[n]

print(fib_bottom_up(20000))
..684684301719893411568996526838242546875
import sys
print("Python Recursive Limitation = ", sys.getrecursionlimit())
import sys
sys.setrecursionlimit(3000)