Генератор скользящего среднего на Python со сбросом окна

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

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

Сглаживающий фильтр со сбросом

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

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

Если входной поток исчерпался либо внешний потребитель досрочно закрыл сам фильтр через close(), блок finally гарантированно вызывает close() у нижележащего источника. Если же фильтр закрыли еще до первого обращения к нему, его тело не начинает выполняться и входящий генератор остается нетронутым.

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

Что уже дано

В среде исполнения доступны вспомогательные функции make_telemetry_source и observe_reset_generator, моделирующие и отслеживающие поведение источников и генераторов. В заготовке решения объявлена функция-генератор resettable_window(source, width), тело которой вам предстоит реализовать.

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

Реализуйте функцию resettable_window(source, width).

Параметры функции:

  • source — однократный итерируемый источник элементов (от 0 до 1000 записей в тестовых последовательностях), выдающий конечные числа int и float в диапазоне от -1 000 000 до 1 000 000, а также строковые токены 'RESET'. Объект имеет метод close(), вызов которого гарантированно не выбрасывает исключений. Чтение из source может прерываться ошибками;
  • width — целое число от 1 до 128, задающее размер скользящего окна ().

Функция должна возвращать нативный генератор Python со следующим поведением:

  • Вызов resettable_window(source, width) возвращает незапущенный генератор: создание генератора или его вызов close() до первого обращения next() не производят чтений из source и не вызывают source.close().
  • Чтение из source выполняется строго по требованию (on demand) до получения очередного значения: нельзя считывать элементы наперёд дальше, чем необходимо для отдачи следующего результата окна или сброса.
  • Пока с момента старта или последнего сброса не получено хотя бы width числовых замеров, частичные средние не генерируются.
  • Как только накопилось width числовых замеров, каждый последующий числовой замер выдаёт через yield среднее арифметическое последних width числовых значений в виде числа с плавающей точкой float.
  • Каждый встреченный маркер 'RESET' очищает все накопленные данные текущего окна и выдаёт через yield ровно одно значение 0.0. Это правило действует в том числе для нескольких маркеров 'RESET' подряд или маркеров, встреченных до накопления полного окна.
  • При штатном исчерпании источника, возникновении ошибки чтения из source, передаче исключения от потребителя через throw() в запущенный генератор или досрочном закрытии через close() запущенного генератора метод source.close() должен быть вызван ровно один раз в блоке finally.
  • Запрещено выполнять yield внутри финализации (при обработке закрытия генератора).
  • Генератор, приостановленный после выдачи очередного значения, ещё не знает об исчерпании источника; source.close() вызывается, когда генератор возобновляется до конца потока либо закрывается явно.
  • Ошибки источника или потребителя должны беспрепятственно всплывать дальше, если закрытие source.close() прошло успешно. Никакой дополнительной валидации входных типов реализовывать не требуется.

Ввод и вывод

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

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

source = make_telemetry_source([1, 3, 5, 'RESET', 4, 8])
print(list(resettable_window(source, 2)))
print(source.close_calls)

Вывод:

[2.0, 4.0, 0.0, 6.0]
1
РешениеPython

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

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

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