Класс-декоратор Python: баланс доступных вызовов функции
Напишите решение на Python и проверьте его на странице.
Другие упражнения по этой теме: Классы-декораторы Python: задачи на call, методы и состояние.
Накопитель зарядов заклинания
В настольной тактической игре заклинание сопряжено с накопителем зарядов. Изначально баланс равен нулю, поэтому без предварительной зарядки применить магию нельзя: попытка активации с нулевым запасом не вызывает целевую функцию, а сразу завершается служебным исключением опустошения.
Мастер игры может в любой момент пополнить накопитель через отдельный метод декоратора, прибавив нужное число зарядов к текущему остатку без сброса уже накопленных единиц. Если же заклинание запускается при положительном балансе, оно исполняется, а ровно один заряд списывается строго после успешного завершения. Если во время работы заклинания возникает ошибка, заряд не расходуется, а само исключение беспрепятственно всплывает наружу.
Реализуйте класс-декоратор с методом пополнения баланса, который защищает функцию от вызова при пустом накопителе и списывает заряд только после её успешного выполнения.
Что уже дано
При выполнении кода уже объявлен класс исключения EmptyCharges, унаследованный от LookupError. Также доступны вспомогательные функции make_call_probe и observe_call_probe для отслеживания вызовов, которые не нужно реализовывать самостоятельно.
Вам предстоит реализовать методы класса SpellCharges.
Что нужно сделать
Реализуйте класс-декоратор SpellCharges со следующим поведением:
- Конструктор
__init__(self, func)принимает целевую функциюfunc(обычный вызываемый объект уровня модуля) и сохраняет её. При создании каждый экземпляр начинает работу с нулевым балансом зарядов (0). - Метод
add_charges(self, amount)принимает целое неотрицательное числоamount(от0до1000) и прибавляет его к текущему остатку зарядов. Требований к возвращаемому значению метода нет. - Метод
__call__(self, *args, **kwargs)обрабатывает вызов задекорированного заклинания: - Если текущий баланс зарядов равен
0, декорированная функцияfuncне вызывается вовсе; метод сразу возбуждает исключениеEmptyCharges()без обязательного сообщения. - Если текущий баланс строго больше
0, метод вызывает исходную функциюfunc(*args, **kwargs)с неизменными позиционными и именованными аргументами. - Если вызов функции
funcзавершился успешно, метод списывает с баланса ровно1заряд и возвращает результат выполненияfunc. - Если вызов функции
funcпривёл к исключению, баланс зарядов остаётся неизменным (заряд не тратится), а исходный объект исключения распространяется дальше без перехвата или подмены.
Правила работы и ограничения:
- Суммарное количество операций вызова и пополнения не превышает
1000. - Декорирование методов классов, связывание контекста (
__get__), время жизни зарядов (TTL), приоритеты, формулы расчёта маны и повторные вызовы при ошибках реализовывать не требуется. - Хранить баланс в публичном атрибуте с фиксированным именем не требуется.
Ввод и вывод
Стандартные потоки stdin и stdout не используются: считывать ввод и выводить данные через print() не требуется.
После выполнения вашего скрипта проверяющая система находит в глобальной области видимости класс верхнего уровня SpellCharges, оборачивает им тестовые функции и напрямую проверяет вызовы, пополнение зарядов и обработку исключений.
Пример использования
probe = make_call_probe([["return", "light"]])
spell = SpellCharges(probe.compute)
spell.add_charges(1)
print(spell())
print(observe_call_probe(probe)["call_count"])
Вывод:
light 1
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Связанные задачи
- Класс-декоратор Python: когда вызывается init
- Класс-декоратор метода Python: почему теряется self
- Класс-декоратор Python: ограничение изменения результата между вызовами
- Класс-декоратор Python: изменение аргумента первых N вызовов
- Класс-декоратор Python: буфер событий и пакетная запись
- Класс-декоратор Python: переключение между основной и резервной репликой
