Почему функция, которая возвращает себя max из рекурсии в python 3

Почему этот код дает ошибку: RuntimeError: maximum recursion depth exceeded during compilation ? print_test никогда не вызывает себя, поэтому я думаю, что это не рекурсивная функция.

 def print_test(): print("test") return print_test print_test() #prints 'test' print() #a quick way of writing "print_test()()()()()()()()()()()()()..." eval("print_test"+"()"*10000) #should print 'test' 10000 times 

Когда я протестировал его, он работал в Python 2.7.7rc1, но дал ошибку в Python 3.3.5. Pdb дает стек коротких вызовов, в отличие от высокого, который обычно существует при превышении максимальной глубины рекурсии.

 Traceback (most recent call last): File "/usr/lib/python3.3/pdb.py", line 1662, in main pdb._runscript(mainpyfile) File "/usr/lib/python3.3/pdb.py", line 1543, in _runscript self.run(statement) File "/usr/lib/python3.3/bdb.py", line 405, in run exec(cmd, globals, locals) File "<string>", line 1, in <module> File "/home/beet/overflow.py", line 1, in <module> def print_test(): 

Мне интересно это из любопытства, и понимаю, что это не будет лучшая практика программирования.

2 Solutions collect form web for “Почему функция, которая возвращает себя max из рекурсии в python 3”

Я считаю, что это связано с проблемой № 5765 .

Примените ограничение жесткой рекурсии в компиляторе [начиная с 3.3]

Не 100% уверен, но этот код работает на 3.2.3 :

 def f(): return f eval("f" + "()" * 10000) 

но сбой на моем 3.4.1, который оставляет меня подозревать, что это изменение вызвало это. Если кто-то подтвердит или опровергнет это, это будет довольно круто.

eval делает компиляцию. Он может обнаружить, что вы хотите глубже входить в вызовы, чем sys.getrecursionlimit() .

Рекурсия может быть как прямой (функция вызывает непосредственно), либо косвенной (функция вызывается другой функцией, которая в свою очередь была однажды вызвана этой функцией). Но когда глубина вызова больше ожидаемой (1000 для реализации Python на момент написания), вызов может быть частью косвенной рекурсии, которая требует еще более глубокого, чтобы проявить себя как рекурсивный . Другими словами, если максимальная глубина вызова достигнута (и глубина разумна, чтобы думать таким образом), это хорошо, чтобы назвать ее рекурсией, которая не может быть выполнена .

Окончательный ответ можно найти в источниках … Но мне было просто любопытно, поэтому я сделал следующий эксперимент. Я попытался написать код, который определяет достаточное количество различных функций (с пронумерованными идентификаторами), которые вызывают следующий, кроме последнего, который на самом деле не вызывает рекурсивно первый.

 def fn1(): print('fn1() is going to call fn2()') fn2() def fn2(): print('fn2() is going to call fn3()') fn3() def fn3(): print('fn3() does not call anything.') fn1() 

Последняя строка запускает вложенные вызовы и печатает.

 fn1() is going to call fn2() fn2() is going to call fn3() fn3() does not call anything. 

Мы можем генерировать источник как строку, а затем мы можем использовать встроенную функцию compile а затем exec ее:

 #!python3 import textwrap n = 1000 print('n =', n) lst = [] for i in range(1, n+1): if i == n: fndef = textwrap.dedent('''\ def fn{}(): print('fn{}() does not call anything.') fn1() '''.format(i, i)) else: fndef = textwrap.dedent('''\ def fn{}(): print('fn{}() is going to call fn{}()') fn{}() '''.format(i, i, i+1, i+1)) if n <= 10: print(fndef) lst.append(fndef) ast = compile('\n'.join(lst), '<string>', 'exec') exec(ast) 

Обратите внимание на n = 1000 в начале источника. Когда исполняемый файл и stdout и stderr перенаправлены на файлы, я мог наблюдать:

 n = 1000 fn1() is going to call fn2() fn2() is going to call fn3() fn3() is going to call fn4() ... fn992() is going to call fn993() fn993() is going to call fn994() fn994() is going to call fn995() Traceback (most recent call last): File "a.py", line 28, in <module> exec(ast) File "<string>", line 4000, in <module> File "<string>", line 3, in fn1 File "<string>", line 7, in fn2 File "<string>", line 11, in fn3 ... File "<string>", line 3967, in fn992 File "<string>", line 3971, in fn993 File "<string>", line 3975, in fn994 File "<string>", line 3978, in fn995 RuntimeError: maximum recursion depth exceeded 

Вывод: Python называет его рекурсией не только во время eval когда он является рекурсией, но еще не выполнен (как показывает вопрос). Python может называть его рекурсией даже в случае, когда на самом деле нет рекурсии.

Лучшее заключение: кто заботится, когда ясно, что код может быть рекурсией или нет, во время компиляции или во время выполнения. В любом случае это не сработает 🙂

  • Возвращение уникальных совпадений с использованием regex в python
  • Многопоточность в Tkinter GUI, потоки в разных классах
  • Неверный ответ в SPOJ `CUBERT`
  • peewee - Определить модели отдельно от инициализации Database ()
  • Как преобразовать двоичный код в число с плавающей запятой
  • Python 3.3 - Юникод-объекты должны быть закодированы перед хэшированием
  • Имя «xrange» не определено в Python 3
  • структуры переменной длины ctypes
  • Python - лучший язык программирования в мире.