python不能無限的遞歸調(diào)用下去。并且當(dāng)輸入的值太大,遞歸次數(shù)太多時(shí),python 都會(huì)報(bào)錯(cuò)
RecursionError: maximum recursion depth exceeded in comparison
首先說結(jié)論,python解釋器這么會(huì)限制遞歸次數(shù),這么做為了避免"無限"調(diào)用導(dǎo)致的堆棧溢出。
tail recursion
tail recursion 就是指在程序最后一步執(zhí)行遞歸。這種函數(shù)稱為 tail recursion function。舉個(gè)例子:
def fact(n):
if n == 0:
return 1
return n * fact(n-1)
這個(gè)函數(shù)就是普通的遞歸函數(shù),它在遞歸之后又進(jìn)行了 乘 的操作。 這種普通遞歸,每一次遞歸調(diào)用都會(huì)重新推入一個(gè)調(diào)用堆棧。
把上述調(diào)用改成 tail recursion function
def fact(n, a=1):
if n == 0:
return a
return fact(n - 1, n * a)
tail recursion 的好處是每一次都計(jì)算完,將結(jié)果傳遞給下一次調(diào)用,然后本次調(diào)用任務(wù)就結(jié)束了,不會(huì)參與到下一次的遞歸調(diào)用。這種情況下,只重復(fù)用到了一個(gè)堆棧。因此可以優(yōu)化結(jié)構(gòu)。就算是多次循環(huán),也不會(huì)出現(xiàn)棧溢出的情況。這就是 tail recursion optimization 。
c和c++都有這種優(yōu)化, python沒有,所以限制了調(diào)用次數(shù),就是為了防止無限遞歸造成的棧溢出。
如果遞歸次數(shù)過多,導(dǎo)致了開頭的報(bào)錯(cuò),可以使用 sys 包手動(dòng)設(shè)置recursion的limit
def fact(n):
if n == 0:
return 1
return n * fact(n-1)
if __name__ == '__main__':
f = int(input('input number: \n'))
print(fact(f))
# 當(dāng)你輸入100時(shí),正常輸出結(jié)果.
# 當(dāng)你輸入1000時(shí)。python 會(huì)報(bào)錯(cuò): maximum recursion depth exceeded in comparison
手動(dòng)放大 recursionlimit 限制:
import sys
sys.setrecursionlimit(10**6)
def fact(n):
if n == 0:
return 1
return n * fact(n-1)
if __name__ == '__main__':
f = int(input('input number: \n'))
print(fact(f))
# 此時(shí)輸入1000, 有正常計(jì)算結(jié)果返回