python solution.py

Счётчик вызовов через декоратор Python

Оберните функцию так, чтобы каждый декоратор вёл собственный счётчик и не менял результат вызова.

  • ЯзыкPython
  • УровеньСредний
  • НавыкЗамыкания, декораторы и атрибуты функций

Контекст

Мобильный SDK продуктовой аналитики оброс трекерами: одна функция шлёт события экранов, другая — клики, третья — покупки. Команде роста нужно знать, сколько раз приложение дёрнуло каждый трекер за сессию, но вписывать counter += 1 в каждую функцию — значит размазать учёт по всему коду. Декоратор решает это одним движением: счётчик живёт в обёртке, а сами трекеры не меняются ни на строку.

Задача

Реализуйте декоратор count_calls(fn): он принимает функцию и возвращает обёртку, которая ведёт счётчик собственных вызовов в атрибуте calls.

Правила

  1. Сразу после декорирования wrapper.calls == 0 — ещё до первого вызова.
  2. Каждый вызов обёртки увеличивает calls на 1 и вызывает fn со всеми переданными аргументами — и позиционными, и именованными (*args, **kwargs).
  3. Результат fn возвращается без изменений.
  4. Счётчики разных задекорированных функций независимы: у каждой — своя обёртка и свой calls.
  5. Имя обёртки не сохраняем — осознанное упрощение.

Примеры

@count_calls
def track_event(name, value=1):
    return f"{name}:{value}"

track_event.calls
# 0

track_event("открытие_экрана")
# "открытие_экрана:1"

track_event("клик_по_кнопке", value=3)
# "клик_по_кнопке:3"

track_event.calls
# 2

Где это пригодится

Счётчик вызовов — простейшая метрика, с которой начинается любой мониторинг: сколько раз дёрнули ручку API, сколько событий ушло в очередь. А приём «состояние в атрибуте обёртки» — основа более серьёзных декораторов: кэшей, ограничителей частоты, сборщиков статистики.

Двигайтесь по одному шагу

Подсказка 1

Создайте функцию-обёртку внутри декоратора и установите её calls до возврата.

Подсказка 2

Передавайте исходной функции все позиционные и именованные аргументы.

Подсказка 3

Счётчик должен принадлежать конкретной обёртке, а не общей глобальной переменной.

Как декоратор хранит состояние обёртки

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

Не оставляйте задачу изолированной