Класс-декоратор Python: сохранение каждого N-го результата

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

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

Периодический снимок результатов

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

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

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

Что уже дано

В заготовке кода представлен класс SnapshotSampler с методами __init__, __call__ и take_snapshot. Вспомогательная функция observe_scheduled_snapshots доступна во время проверки и служит для тестирования работы экземпляров.

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

Реализуйте класс SnapshotSampler(function, step):

  • Конструктор принимает два аргумента:
  • function — обычную синхронную вызываемую функцию;
  • step — целое положительное число шага интервала от 1 до 100.
  • Экземпляр хранит общедоступный атрибут snapshots — список, в который в порядке получения добавляются зафиксированные результаты.
  • Метод __call__(*args, **kwargs) передаёт аргументы в целевую функцию без изменений и возвращает её реальный результат:
  • если вызов целевой функции завершается исключением (производным от BaseException), это исключение пробрасывается без изменений, счёт успешных вызовов не изменяется, а в snapshots ничего не добавляется;
  • фиксируются результаты успешных вызовов: 1-й, затем -й и далее с тем же шагом;
  • в проверочных сценариях результаты представляют собой неизменяемые типы (int, bool, str, None, tuple); создавать их глубокие копии не требуется.
  • Метод take_snapshot():
  • не вызывает целевую функцию и возвращает None;
  • регистрирует запрос на обязательное сохранение результата ровно следующего успешного вызова целевой функции;
  • запрос на внеочередной снимок сохраняется при возникновении ошибок в последующих вызовах, пока не произойдёт успешный расчёт;
  • после фиксации этого результата отсчёт регулярного интервала сбрасывается и возобновляется заново от этой точки (следующий регулярный снимок произойдёт через step успешных вызовов);
  • если внеочередной запрос совпадает с очередным регулярным сохранением, результат записывается в snapshots ровно один раз.
  • Независимые экземпляры класса не влияют на состояние друг друга (поддерживается чередование от 1 до 3 экземпляров, до 1000 вызовов на каждый).

Ввод и вывод

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

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

sampler = SnapshotSampler(lambda value: value * 10, 3)
for value in (1, 2, 3, 4):
    sampler(value)
print(sampler.snapshots)
sampler.take_snapshot()
sampler(5)
print(sampler.snapshots)

Вывод:

[10, 40]
[10, 40, 50]
РешениеPython

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

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

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