Python棧溢出

Python 棧溢出

python3.5.4
遞歸函數最噁心的時候莫非棧溢出(Stack overflow)。

如何解決?

人爲設置遞歸深度

使用python寫的遞歸程序如果遞歸太深, 那麼極有可能因爲超過系統默認的遞歸深度限制而出現錯誤。一般默認遞歸長度在1000左右。
RuntimeError: maximum recursion depth exceeded in comparison

顯然此時我們可以人爲修改

import sys
sys.setrecursionlimit(1000000) #括號中的值爲遞歸深度

尾遞歸優化

注:這只是一種思維的科普
解決遞歸調用棧溢出的另一種方法是通過尾遞歸優化,事實上尾遞歸和循環的效果是一樣的,所以,把循環看成是一種特殊的尾遞歸函數也是可以的。

尾遞歸是指,在函數返回的時候,調用自身本身,並且,return語句不能包含表達式。這樣,編譯器或者解釋器就可以把尾遞歸做優化,使遞歸本身無論調用多少次,都只佔用一個棧幀,不會出現棧溢出的情況。

上面的fact(n)函數由於return n * fact(n - 1)引入了乘法表達式,所以就不是尾遞歸了。要改成尾遞歸方式,需要多一點代碼,主要是要把每一步的乘積傳入到遞歸函數中:

def fact(n):
    return fact_iter(n, 1)

def fact_iter(num, product):
    if num == 1:
        return product
    return fact_iter(num - 1, num * product)

可以看到,return fact_iter(num - 1, num * product) 僅返回遞歸函數本身,num - 1和num * product在函數調用前就會被計算,不影響函數調用。

fact(5)對應的fact_iter(5, 1)的調用如下:

===> fact_iter(5, 1)
===> fact_iter(4, 5)
===> fact_iter(3, 20)
===> fact_iter(2, 60)
===> fact_iter(1, 120)
===> 120

尾遞歸調用時,如果做了優化,棧不會增長,因此,無論多少次調用也不會導致棧溢出。

遺憾的是,大多數編程語言沒有針對尾遞歸做優化,Python解釋器也沒有做優化,所以,即使把上面的fact(n)函數改成尾遞歸方式,也會導致棧溢出。

Python標準的解釋器沒有針對尾遞歸做優化,任何遞歸函數都存在棧溢出的問題

小結

方法一:人爲修改默認遞歸長度
方法二:人爲修改python解釋器,將其優化,會十分有趣

如果您看到這篇文章有收穫或者有不同的意見,歡迎點贊或者評論。
python:190341254
丁。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章