Декоратор Python: сглаживание повторных координат с допустимым отклонением
Напишите решение на Python и проверьте его на странице.
Другие упражнения по этой теме: Декораторы Python: задачи на retry, rate limiter, кэш и Circuit Breaker.
Сглаживающий коридор видоискателя
Цифровой видоискатель наводит телескоп на звёзды, но атмосферное дрожание воздуха заставляет датчик непрерывно отправлять микроколебания одного и того же сектора. Чтобы не перегружать оптический привод постоянными мелкими корректировками, поток координат сглаживают с помощью параметризованного декоратора с заданным коридором допустимой погрешности.
Декоратор сохраняет в замыкании последнее опорное значение сырой координаты и последний готовый отклик оптики. При самом первом обращении целевая функция оптики обязательно вызывается, полученная координата запоминается как опорная, а вычисленный результат кэшируется. При каждом следующем замере декоратор сравнивает новое значение с сохранённой опорной координатой: если модуль их разности меньше либо равен ширине коридора, функция не запускается и возвращается прежний отклик. Если же отклонение строго превышает ширину коридора, целевая функция вызывается с новой координатой, которая становится новой опорной точкой и обновляет кэшированный отклик.
Реализуйте параметризованный декоратор сглаживающего коридора, который отсекает дрожание датчика и обращается к целевой функции только при первом пуске и при строгом выходе замера за границы допуска.
Что уже дано
В редакторе представлена заготовка функции deadband_cache(width) с заглушкой NotImplementedError.
При тестировании также доступна вспомогательная функция observe_deadband_calls(width, events, responses, related=False, keyword=False), которая создаёт независимые декорированные функции, имитирует замеры и собирает статистику обращений к целевым операциям. Реализовывать её самостоятельно не нужно.
Что нужно сделать
Реализуйте функцию-фабрику deadband_cache(width).
Она принимает параметр width — конечное неотрицательное число (int или float, от 0 до 1 000 000) — и возвращает декоратор. Этот декоратор принимает функцию func, работающую с оптикой, и возвращает функцию-обёртку.
Правила работы обёртки:
- Целевая функция
funcпринимает ровно одну координатуx. Обёртка должна поддерживать передачу координаты как позиционным аргументом, так и по имени (x=...), и при реальном вызовеfuncобязана передавать исходный переданный объект аргумента без подмены. - Координаты представляют собой конечные числа семейства
int/float(включаяbool) в диапазоне от -1 000 000 до 1 000 000. Никакой хэшируемости от координат или возвращаемых значений не требуется. - Целевая функция возвращает произвольный объект Python (включая
None, ложные значения или изменяемые контейнеры). Никаких проверок на ошибки внутриfuncдобавлять не требуется; последовательность вызовов для каждой обёртки составляет от 0 до 1000 обращений. - При самом первом вызове обёртки целевая функция
funcвызывается всегда. Полученная координата сохраняется как начальная опорная точка, а возвращённый объект — как текущий кэшированный отклик. - При последующих вызовах вычисляется модуль разности
abs(new_coordinate - anchor): если он меньше либо равенwidth, обращение кfuncпропускается, а обёртка возвращает сохранённый кэшированный объект отклика. Попадание в коридор допуска не сдвигает опорную точку. - Только если
abs(new_coordinate - anchor) > width, обёртка снова вызываетfuncс новой координатой, обновляя и опорную точку, и сохранённый объект отклика. - Сравнение выполняется строго по координатам, а не по значениям откликов.
- Каждая задекорированная функция имеет полностью независимое внутреннее состояние (свою опорную координату и свой сохранённый отклик), даже если они были созданы одной и той же фабрикой
deadband_cache.
Ввод и вывод
Стандартные потоки ввода stdin и вывода stdout в решении не используются: считывать ввод и вызывать print() не нужно. После выполнения кода учащегося проверяющая система считывает из пространства имён модуля функцию верхнего уровня deadband_cache и вызывает её с проверочными аргументами.
Пример использования
calls = []
@deadband_cache(2)
def optics(x):
calls.append(x)
return {'coordinate': x}
first = optics(10)
print(optics(12) is first)
print(optics(13))
print(calls)
Вывод:
True
{'coordinate': 13}
[10, 13]
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Связанные задачи
- Functools.wraps в Python: имя функции и атрибут wrapped
- Декоратор Circuit Breaker на Python: остановка вызовов после сбоев
- Декораторы Python: проверка цепочки wrapped и метаданных функции
- Декоратор Python: логирование только медленных вызовов
- Кэширование Python: постройте ключ из выбранных аргументов функции
- Rate limiter на Python: декоратор со скользящим окном запросов
