2012-06-27 55 views
6

爲什麼/它如何創建一個看似無限循環?錯誤地,我認爲這會導致某種形式的堆棧溢出類型錯誤。爲什麼這個Python腳本創建一個無限循環? (遞歸)

i = 0 

def foo() : 
    global i 

    i += 1 
    try : 
     foo() 
    except RuntimeError : 
     # This call recursively goes off toward infinity, apparently. 
     foo() 

foo() 

print i 
+5

那麼,你只要繼續調用'foo',沒有停止條件,所以它會一直持續遞增。甚至當你發生異常時,你就會緩解_again_。 –

+0

不應該Python內存不足或什麼東西?或者在'RuntimeError'之後清除調用堆棧? – rectangletangle

+0

可能蟒蛇被優化成迭代 – Blorgbeard

回答

4

如果你的代碼更改爲

i = 0 
def foo(): 
    global i 
    i += 1 
    print i 
    try : 
     foo() 
    except RuntimeError : 
     # This call recursively goes off toward infinity, apparently. 
     foo() 
    finally: 
     i -= 1 
     print i 

foo() 

你會觀察到輸出振盪短低於999(1000是Python的默認遞歸限制)。這意味着,當達到限制(RuntimeError)的foo()去年呼叫被終止,而另一個被掀起立即更換。

如果提高一個KeyboardInterrupt你觀察一下整個跟蹤被立即終止。


UPDATE

有趣的foo()第二個電話不被try ... except - 阻塞保護了。因此,應用程序將最終終止。如果將遞歸限制設置爲較小的數字,則這變得顯而易見。輸出爲sys.setrecursionlimit(3)

$ python test.py 
1 
2 
1 
2 
1 
0 
Traceback (most recent call last): 
    File "test.py", line 19, in <module> 
    foo() 
    File "test.py", line 14, in foo 
    foo() 
    File "test.py", line 14, in foo 
    foo() 
RuntimeError 
6

如果超過遞歸限制,將會引發RuntimeError異常。

既然你趕上這個例外,你的機器是要繼續,但你只需要添加一個單一的全球int值,它不會使用太多的內存。

您可以sys.setrecursionlimit()設置遞歸限制。 電流限制可以在sys.getrecursionlimit()找到。

>>> import sys 
>>> sys.setrecursionlimit(100) 
>>> 
>>> def foo(i): 
...  i += 1 
...  foo(i) 
... 
>>> foo(1) 
Traceback (most recent call last): 
    ... 
    File "<stdin>", line 3, in foo 
RuntimeError: maximum recursion depth exceeded 
>>> 

如果你想用盡內存嘗試消耗更多。

>>> def foo(l): 
...     l = l * 100 
...     foo(l) 
... 
>>> foo(["hello"]) 
Traceback (most recent call last): 
    ... 
  File "<stdin>", line 2, in foo 
MemoryError 
>>> 
相關問題