Этот вопрос проверяет понимание декораторов, замыканий и управления состоянием между вызовами функции.
Декоратор — это функция, которая оборачивает другую функцию и может изменять её поведение. Чтобы считать количество вызовов, нужно сохранить счётчик во внешней области видимости (замыкание). При каждом вызове счётчик увеличивается, и если он превышает лимит, выбрасывается исключение. Такой подход часто используется для ограничения доступа, защиты ресурсов или отладки.
Декораторы позволяют добавить логику до и после выполнения функции, не изменяя её код напрямую.
Определение: Декоратор — это функция, которая принимает другую функцию и возвращает новую функцию с расширенным или изменённым поведением.
Нам нужно:
Передать лимит вызовов в декоратор
Хранить счётчик между вызовами
Проверять лимит при каждом вызове
Для этого используется:
Функция-декоратор с аргументами
Замыкание для хранения состояния
def call_limit(max_calls):
def decorator(func):
calls = 0
def wrapper(*args, **kwargs):
nonlocal calls
calls += 1
if calls > max_calls:
raise RuntimeError("Превышен лимит вызовов функции")
return func(*args, **kwargs)
return wrapper
return decorator
@call_limit(3)
def hello():
print("Hello")
hello()
hello()
hello()
hello() # здесь будет исключение
nonlocalПеременная calls объявлена во внешней функции decorator
Ключевое слово nonlocal позволяет изменять её значение внутри wrapper
Ограничение количества попыток (rate limit)
Защита от повторных вызовов
Отладка и сбор статистики
Декораторы удобны для добавления счётчиков и ограничений без изменения бизнес-логики.
Замыкания позволяют хранить состояние между вызовами функции.