2012-06-27 13 views
6

यह एक असीमित अनंत लूप क्यों बनाता है? गलत है, मुझे लगता है कि यह एक ढेर ओवरफ्लो प्रकार त्रुटि के कुछ रूप का कारण बन जाएगा। यदि प्रत्यावर्तन सीमा पार हो गई हैयह पायथन स्क्रिप्ट एक अनंत लूप क्यों बनाती है? (रिकर्सन)

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' बुला, कोई रोक शर्त के साथ रहते हैं, तो यह हमेशा के लिए recurse जारी रहेगा। और जब भी आपको अपवाद मिलता है, तो आप _again_ की पुनरावृत्ति करते हैं। –

+0

पाइथन स्मृति या कुछ से बाहर नहीं होना चाहिए? या 'रनटाइमर' के बाद कॉल स्टैक साफ़ हो गया है? – 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 अजगर के डिफ़ॉल्ट प्रत्यावर्तन सीमा जा रहा है) कम झूल रहे हैं। इसका मतलब है, जब सीमा हिट होती है (RuntimeError) कि foo() का अंतिम कॉल समाप्त हो गया है, और दूसरा इसे तुरंत बदलने के लिए सेट किया गया है।

यदि आप KeyboardInterrupt उठाते हैं तो आप देखेंगे कि पूरे ट्रेस को एक बार में कैसे समाप्त किया जा रहा है।


अद्यतन

दिलचस्प बात यह है foo() की दूसरी कॉल try ... except -block द्वारा अब और संरक्षित नहीं है। इसलिए आवेदन वास्तव में अंततः समाप्त हो जाएगा। यदि आप रिकर्सन सीमा को एक छोटी संख्या में सेट करते हैं, तो यह गारंटी बन जाता है, उदा। 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 
>>>