遞歸函數不是帝龜啊!:一個函數調用了它本身自己就叫作遞歸函數
定義一個比較糟糕的函數調用自身:
你會發現它調用test()的時候,它惟一的函數內容是打印myoffer而後returntest(),再回到定義函數,打印myoffer,而後return test()一直循環往復;
這就有疑問了工具
是否是會一直執行下去呢,理論上它會一直執行下去直到消耗掉全部內存,其實Python3設置了遞歸默認深度是100層,到達以後就會報錯。不過在寫爬蟲工具的時候就可能不止100層了,因此咱們就要自力更生了。spa
這樣深層次的調用就會致使「棧溢出」就比如一個杯子它有本身的最大容量,超過了這個容量就會溢出。
來我的道點的例子解釋帝龜和棧溢出:求1-100的階乘。3d
先分析:
想要獲得的結果1×2×3×…×100
能夠拆分紅100×函數(99)【函數(99)能夠完成1×2×3×…×99 】
能夠拆分紅 99×函數(98)【函數(99)能夠完成1×2×3×…×98】
……
……
…….
能夠拆分紅2×函數(1)【函數(1)能夠完成1×2】正確的解法以下blog
如今來了解一下這隻龜,先拿一個print(test(3))來剖析遞歸
第一次程序執行時會先傳入3,替換全部numbers,當執行到test(3-1)又要調用test()而後就會傳入2,變爲test(numbers=2)下面的程序。
同理執行到test(2-1)又要再次調用test(),變爲test(numbers=1)下面的程序
直接執行else後的程序返回1
注意:一個函數調用return有兩種含義:返回一個值或結束當前函數;ip
因此說當return 1時第二個程序中的test(2-1)就會替換爲return 2×1
接着就會執行這個return 2×1時,第一個程序中的test(3-1)就會替換爲return 3×2×1
當執行這個return 3×2×1時,程序就會執行結果print(test(3)),同理要執行print(test(100))也是同樣的原理,這就是帝龜。內存
好啦如今理解了帝龜就能夠更透徹明白棧溢出了it
第一步當程序執行print(test(3))這玩意的時候,就要調用函數test(number=3),而後執行下面這個函數
執行好後呢,先把這個3放到杯子底下,而後執行numbers=2,就把2再放到杯子裏,一層層上疊(就是在內存中存儲好,爲了當返回執行return2×1時,可以識別3×test(3-1)並替換爲return 3×2×1,其它的相似,當返回執行return1時,可以識別2×test(2-1)並替換爲return 2×1)
因此說每次調用本身函數的時候呢就要在杯子中裝點東西,當你調用循環的次數是1000000或者更大,杯子總有滿的時候,等到裝不下的時候就叫作「棧溢出」了。class
至於爲甚麼叫「棧(stack)溢出」怎麼上檔次的名字呢
上面說了存東西的時候都是從杯底往上一層層的疊加(調用一次函數,棧就會加一層棧幀),到你要取的時候只能先從上面拿了(函數返回棧就會減一層棧幀),杯子是有最大容量的(棧的大小不是無限的,遞歸調用過多就會棧溢出)總結:這種存儲特性「先進後出」
注意:爲何上面的例子numbers=1要單獨處理呢,由於當numbers傳入1時,就會變成test(1-1),沒有到0的階乘,這樣結果就會變成0.