Класс-декоратор Python: ограничение глубины рекурсии

Напишите решение на Python и проверьте его на странице.

Другие упражнения по этой теме: Классы-декораторы Python: задачи на call, методы и состояние.

Ограничитель глубины вызовов

Игровой бот исследует процедурный лабиринт с помощью рекурсивной функции, переходящей из комнаты в комнату. Чтобы алгоритм не уходил в бесконечные петли и не тратил ресурсы впустую, вызовы этой функции защищают специальным классом-декоратором с настраиваемым лимитом глубины.

Декоратор следит за количеством текущих вложенных шагов. Если уровень активной рекурсии уже достиг установленного предела, декоратор блокирует попытку пройти дальше и сразу возвращает None, вообще не вызывая целевую функцию. Когда же порог ещё не превышен и шаг действительно выполняется, счётчик активной глубины увеличивается на единицу, а при возврате значения или ошибке строго откатывается обратно. Исторический максимум глубины при этом обновляется только для тех вызовов, которые реально состоялись.

Реализуйте класс-декоратор, который отсекает вызовы на границе лимита, надёжно восстанавливает счётчик текущей глубины и сохраняет наибольшую глубину среди фактически запущенных шагов.

Что уже дано

В редакторе представлена заготовка класса DepthGuard с методами __init__ и __call__, которые вам предстоит реализовать. Дополнительная вспомогательная функция observe_depth_guard уже доступна в тестовом окружении для проверки сценариев выполнения; реализовывать её не требуется.

Что нужно сделать

Реализуйте класс DepthGuard со следующим поведением:

  • Конструктор DepthGuard(func, max_depth) принимает исходную синхронную функцию func и целое число max_depth (от 0 до 20) — максимальное допустимое количество одновременно выполняющихся вызовов целевой функции для данного экземпляра декоратора.
  • При инициализации экземпляра атрибуты active_depth и peak_depth устанавливаются равными 0.
  • Экземпляр вызывается через метод __call__(*args, **kwargs) с произвольными позиционными и именованными аргументами, которые должны передаваться в целевую функцию без изменений.
  • Если в момент вызова значение active_depth уже равно max_depth, декоратор немедленно возвращает None. Исходная функция func при этом не вызывается, а значение peak_depth не изменяется.
  • Если лимит ещё не достигнут, перед вызовом целевой функции active_depth увеличивается на 1. Значение peak_depth обновляется наибольшим фактически достигнутым уровнем активной глубины.
  • При завершении фактически запущенного вызова — как при успешном возврате результата, так и при возникновении любого исключения (включая семейство BaseException) — значение active_depth гарантированно возвращается к предыдущему уровню. Зафиксированный максимум peak_depth сохраняется между последующими вызовами.
  • Если целевая функция вернула значение, декоратор возвращает его без изменений. Если целевая функция выбросила исключение, декоратор не подавляет и не подменяет его, а пробрасывает дальше.
  • Каждый созданный экземпляр DepthGuard хранит собственное независимое состояние счетчиков, даже если одна декорированная функция вызывает другую.
  • Реализовывать сохранение метаданных или связывание методов через дескрипторы в этой задаче не требуется.

Ввод и вывод

Стандартные потоки ввода stdin и вывода stdout в решении не используются: считывать ввод и вызывать print() не нужно. После выполнения кода учащегося проверяющая система считывает из пространства имён модуля класс верхнего уровня DepthGuard и вызывает его с проверочными аргументами.

Пример использования

def explore(steps):
    if steps == 0:
        return 'exit'
    return guarded(steps - 1)
guarded = DepthGuard(explore, 2)
print(guarded(3))
print(guarded.active_depth, guarded.peak_depth)
print(guarded(1))

Вывод:

None
0 2
exit
РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Связанные задачи