2012-06-27 3 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

Возможно, python оптимизирует его в итерации – 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 -блоком больше. Поэтому приложение в конечном итоге прекратится. Это станет apparant, если вы установите ограничение рекурсии на меньшее число, например. выход для 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 
>>> 
Смежные вопросы