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

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

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

Монотонная контрольная сумма

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

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

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

Что уже дано

В среде выполнения уже доступен класс служебного исключения MonotonicityError (наследник ValueError). Также доступна вспомогательная утилита observe_monotonic_checksums, реализовывать которую не требуется.

В редакторе представлена заготовка класса MonotonicChecksum с методами __init__, __call__ и reset_baseline(), которые вам предстоит реализовать.

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

Реализуйте класс-декоратор MonotonicChecksum(func) со следующими методами:

  • Конструктор __init__(self, func) принимает синхронный вызываемый объект func, возвращающий конечные числа из семейств целых чисел или чисел с плавающей точкой (включая bool) в диапазоне от -1 000 000 до 1 000 000. Требования к хешируемости возвращаемых чисел отсутствуют.
  • Метод __call__(self, *args, **kwargs) перехватывает вызов декорированной функции:
  • Аргументы *args и **kwargs (включая произвольные изменяемые объекты) передаются в целевую функцию без изменений.
  • Если вызов целевой функции завершается исключением, это исключение беспрепятственно всплывает дальше. Новый эталон при этом не устанавливается, а текущий остаётся неизменным.
  • При успешном выполнении целевой функции (она вызывается строго один раз за обращение) полученное число проверяется на монотонность.
  • Самый первый успешный результат после инициализации декоратора или после вызова reset_baseline() принимается безоговорочно (без сравнения) и становится текущим эталоном.
  • Каждый последующий результат принимается только в том случае, если он строго больше текущего эталона. При соблюдении этого условия возвращается исходный числовой объект, а эталон обновляется до этого значения.
  • Если результат меньше текущего эталона или равен ему, возбуждается исключение MonotonicityError (или его подкласс), а прежний эталон остаётся неизменным.
  • Метод reset_baseline(self) сбрасывает сохранённый эталон текущего экземпляра без обращения к целевой функции. Следующий успешный вызов функции принимается безоговорочно. Возвращаемое значение для reset_baseline() не регламентируется.

Каждый задекорированный объект ведёт собственный независимый эталон. Допустимо от 0 до 1000 последовательных вызовов и сбросов на один декоратор; поддержка рекурсивных или повторно входимых вызовов не требуется.

Ввод и вывод

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

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

@MonotonicChecksum
def checksum(block):
    return sum(block)
print(checksum([1, 2]))
try:
    checksum([3])
except MonotonicityError:
    print('violation')
checksum.reset_baseline()
print(checksum([0]))

Вывод:

3
violation
0
РешениеPython

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

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

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