Класс-декоратор Python: изменение аргумента первых N вызовов

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

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

Щадящий прогрев керамической печи

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

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

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

Что уже дано

В заготовке кода объявлен класс WarmupPower с методами __init__, __call__ и extend, содержащими заглушки raise NotImplementedError.

Во время проверки в среде исполнения также доступна вспомогательная функция observe_warmup_sequence, которую не требуется реализовывать или менять.

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

Реализуйте класс-декоратор WarmupPower:

  • Конструктор __init__(self, function, steps) принимает:
  • function — обычную синхронную вызываемую функцию, чей первый аргумент отвечает за мощность;
  • steps — целое число от 0 до 1000, задающее начальное количество успешных шагов прогрева.
  • Вызов экземпляра через __call__(self, power, *args, **kwargs):
  • принимает power — целое число от 0 до 1 000 000 (может передаваться как первый позиционный аргумент или как именованный аргумент power), а также произвольные остальные аргументы *args и **kwargs;
  • каждый вызов ровно один раз запускает исходную функцию function;
  • если остаток шагов прогрева строго больше нуля, в исходную функцию передаётся урезанная мощность power // 2 (деление нацело с округлением вниз). Все остальные аргументы *args и **kwargs передаются без изменений с сохранением их идентичности;
  • если шаги прогрева исчерпаны (остаток равен 0), аргумент power передаётся в исходную функцию без изменений;
  • успешное завершение вызова функции с пониженной мощностью уменьшает счётчик оставшихся шагов прогрева ровно на 1;
  • если целевая функция завершается исключением (включая любые классы, наследующие от BaseException), это же самое исключение должно беспрепятственно всплыть дальше. Шаг прогрева в этом случае не списывается;
  • при успешном вызове метод возвращает точный результат исходной функции без изменений (с сохранением объектной идентичности).
  • Метод extend(self, steps) -> None:
  • принимает целое неотрицательное число шагов steps (от 0 до 1000) и прибавляет его к текущему остатку шагов прогрева (в том числе после того, как прогрев был полностью исчерпан);
  • не вызывает целевую функцию и возвращает None;
  • вызов extend(0) оставляет оставшееся количество шагов без изменений.
  • Каждый созданный экземпляр WarmupPower хранит полностью независимое состояние прогрева.

Поддержка протокола дескрипторов методов классов, повторные вызовы при сбоях (retries), изменение метаданных функции или валидация неподдерживаемых типов не требуются.

Ввод и вывод

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

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

def inject(power):
    return f"sent:{power}"
warm = WarmupPower(inject, 2)
print(warm(9))
print(warm(9))
print(warm(9))
warm.extend(1)
print(warm(7))

Вывод:

sent:4
sent:4
sent:9
sent:3
РешениеPython

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

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

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