Функция, которая вызывает саму себя, использует рекурсию.
Эта идея встречается повсюду и в математике, и в программировании. Её преимущество в том, что функция может перебирать данные, пока не придёт к результату.
Будьте внимательны, когда пишете такую функцию: легко получить функцию, которая никогда не останавливается или расходует слишком много памяти или ресурсов процессора. Однако при правильном написании рекурсия — это эффективный и математически элегантный способ программирования.
Пример
Рекурсивный обратный отсчёт, начиная с 5:
Вывод: полная программа на Python
def countdown(n):
if n <= 0:
print("Готово!")
else:
print(n)
countdown(n - 1)
countdown(5)
Базовый случай и рекурсивный случай
В любой рекурсивной функции необходимы две части:
- Базовый случай — условие, которое завершает рекурсию
- Рекурсивный случай — место, где функция вызывает саму себя с изменённым аргументом
Уберите базовый случай, и функция будет вызывать себя, пока Python не остановит её ошибкой рекурсии.
Здесь нет ничего важнее базового случая, поэтому всегда проверяйте, что его условие рано или поздно будет достигнуто.
Пример
Определение базового и рекурсивного случаев:
Вывод: полная программа на Python
def factorial(n):
# Базовый случай
if n == 0 or n == 1:
return 1
# Рекурсивный случай
else:
return n * factorial(n - 1)
print(factorial(5))
Последовательность Фибоначчи
Классический пример рекурсии — последовательность Фибоначчи. Она начинается с 0 и 1, а каждое следующее число получается сложением двух предыдущих:
0, 1, 1, 2, 3, 5, 8, 13 и так далее.
Последовательность не имеет конца, и одно и то же правило сложения действует на всём её протяжении.
С помощью рекурсии можно вычислить любое выбранное число последовательности:
Пример
Найдите число на позиции 7 в последовательности Фибоначчи, считая от 0:
Вывод: полная программа на Python
def fibonacci(n):
if n <= 1:
return n
else:
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(7))
Рекурсия и списки
Список можно обрабатывать рекурсивно, работая только с одним элементом при каждом вызове:
Пример
Сложите все элементы списка:
Вывод: полная программа на Python
def sum_list(numbers):
if len(numbers) == 0:
return 0
else:
return numbers[0] + sum_list(numbers[1:])
my_list = [1, 2, 3, 4, 5]
print(sum_list(my_list))
Пример
Найдите наибольшее значение в списке:
Вывод: полная программа на Python
def find_max(numbers):
if len(numbers) == 1:
return numbers[0]
else:
max_of_rest = find_max(numbers[1:])
return numbers[0] if numbers[0] > max_of_rest else max_of_rest
my_list = [3, 7, 2, 9, 1]
print(find_max(my_list))
Ограничение глубины рекурсии
Рекурсия в Python может уходить вглубь лишь до определённого предела. По умолчанию это ограничение обычно составляет около 1000 рекурсивных вызовов.
Это ограничение можно увеличить, если нужна большая глубина, но это может привести к аварийному завершению программы.
Поэтому увеличивайте его осторожно, а для очень глубокой рекурсии подумайте об использовании итерации.
Пример
Выведите текущее ограничение глубины рекурсии:
Вывод: полная программа на Python
import sys
print(sys.getrecursionlimit())
import sys
sys.setrecursionlimit(2000)
print(sys.getrecursionlimit())