Это одно из практических ограничений рекурсии без оптимизации хвостового вызова .
Python имеет защиту от количества рекурсивных вызовов, которые вы можете сделать, чтобы избежать переполнения стека. Это RecursionError
, который вы видите:
Python 3.7.4 (default, Aug 13 2019, 20:35:49)
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> def recursion(n):
... return 1 if n < 2 else n * recursion(n - 2)
...
>>>
>>> string = str(recursion(1000000000000000000))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in recursion
File "<stdin>", line 2, in recursion
File "<stdin>", line 2, in recursion
[Previous line repeated 996 more times]
RecursionError: maximum recursion depth exceeded in comparison
Увеличение является возможным решением, но оно удаляет только встроенную защиту. Если будет сделано достаточно рекурсивных вызовов, вам в конечном итоге не хватит памяти, что является второй ошибкой, которую вы получаете (MemoryError: Stack overflow
или ошибка сегментации в моем случае).
Python 3.7.4 (default, Aug 13 2019, 20:35:49)
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.setrecursionlimit(100000)
>>> def recursion(n):
... return 1 if n < 2 else n * recursion(n - 2)
...
>>> string = str(recursion(1000000000000000000))
Segmentation fault
Идиоматическое решение этой проблемыпроблема в Python заключается в том, чтобы вместо этого использовать итерацию:
def iteration(n):
result = 1
for i in range(n, 1, -2):
result *= i
return result
Выполнение этого примера с исходным вводом (1e18
) не завершится в ближайшее время. По мере роста целого числа для его вычисления требуется все больше времени, поскольку операции требуют использования целочисленных представлений, больших 64-битных (или скольких битов ваш ЦП может представлять с помощью одного регистра).
Тем не менее,это было бы Pythonic решение этой проблемы.