2014-04-09 82 views
8
def f1(): 
    f1() 

我們都知道,調用在Python此功能會產生RuntimeError: maximum recursion depth exceededPython的遞歸RuntimeError

我寫它的sligtly修改後的版本:

def f2(): 
    try: 
     f2() #This line throws an error 
    finally: #except works too 
     f2() #This line does not throw an error! 

第二個功能將永遠運行下去,沒有拋出RuntimeError。更重要的是,我無法阻止它與CtrlC組合。

我不明白爲什麼叫f2()不會拋出RuntimeError。你能解釋一下嗎?

回答

4

爲堆棧滿,它會調用f2直到達到最大遞歸深度。

一旦它到達的是,它提出了一個RuntimeError,這是由finally

這反過來又提出同樣的RuntimeError處理,但是現在到了早期的堆,沿着到finally調用傳遞。

在那裏,它再次超過最大深度。

當一個KeyboardInterrupt被提出時,程序移到finally都是一樣的,不會退出。

它不會在技術上永遠運行,因爲只有一個finally。這就是說,(感謝評論),它允許指數更多的呼叫,這接近無窮大。 100遞歸深度將變成2 == 1267650600228229401496703205376.

如果把每次通話1毫秒,它會採取465十億多年的完成。這只是一個深度100

+0

我相信這最終會成爲實際上最大堆棧幀數中的'O(n ** n)'。所以,相當長一段時間。 – Eevee

+0

我只是自己來實現這個目標。哎呀! – mhlester

+0

或者實際上可能是'O(2 ** n)'。天文數字:) – Eevee

4

例外仍然被拋出,但前Python可以顯示它您呼叫f2()再次

因此,每次引發異常時,都會潛入另一個電話。允許遞歸調用(因爲我們比限制低了一步),我們超過了限制,異常再次發生,finally處理程序在另一個調用中潛入,幾乎是無限的。

CTRL-C由於相同的原因不會結束程序;會引發異常(KeyboardInterrupt),但finally:處理程序再次將您發送回遞歸。

你現在正以這樣一個速度落在繞解釋者的軌道上。

這一切都確實結束,但finally處理程序添加一個指數增長一些額外的調用堆棧之前可以充分放鬆:內try

>>> import sys 
>>> def f2(depth=0, final=0): 
...  try: 
...   print depth 
...   f2(depth + 1, final) 
...  finally: 
...   print 'finally:', final 
...   f2(depth, final + 1) 
... 
>>> sys.setrecursionlimit(5) 
>>> f2() 
0 
1 
2 
3 
finally: 0 
finally: 0 
2 
finally: 1 
finally: 0 
1 
2 
finally: 1 
finally: 1 
1 
finally: 2 
finally: 0 
0 
1 
2 
finally: 1 
finally: 1 
1 
finally: 2 
finally: 1 
0 
1 
finally: 2 
finally: 2 
0 
finally: 3 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 7, in f2 
    File "<stdin>", line 7, in f2 
    File "<stdin>", line 7, in f2 
    File "<stdin>", line 7, in f2 
RuntimeError: maximum recursion depth exceeded 
+1

希望我可以給出另一個+1'你現在正以這樣一個速度進入圍繞解釋器軌道運行的速度' – inspectorG4dget

+0

它會永遠運行還是會最終引發一個異常(非常長時間爲@mhlester建議)? –

+0

@pbackup:它會永遠運行。只有一個堆棧限制,而不是限制的平方根。你只要保持'恢復',然後通過重新應用'try'''ally'處理程序來重新輸入問題。 –

相關問題