Декоратор Python: валидация направления и размера перемещения
Напишите решение на Python и проверьте его на странице.
Другие упражнения по этой теме: Декораторы Python: задачи на retry, rate limiter, кэш и Circuit Breaker.
Ограничитель шага каретки
Блок управления координатным столом принимает команды на перемещение каретки вдоль направляющей рельсы. Чтобы защитить механизм от рывков и холостого дребезга, каждый шаг перед отправкой на двигатель должен проходить строгую проверку.
За перемещениями следит параметризованный декоратор, который настраивается на допустимое направление движения (только вперёд или только назад) и максимальный шаг за один вызов. В замыкании декоратор хранит текущую абсолютную координату каретки, которая изначально равна нулю. Если полученная абсолютная координата совпадает с текущей, нарушает выбранный знак строгого ненулевого приращения или модуль смещения оказывается строго больше допустимого максимума, декоратор не вызывает двигатель и сразу возбуждает ValueError, сохраняя прежнюю координату.
Если шаг корректен, декоратор вызывает целевую функцию двигателя. Новое положение фиксируется в замыкании строго после успешного завершения этого вызова. Если же внутри функции двигателя происходит сбой, сохранённая координата остаётся прежней, а возникшее исключение пробрасывается дальше.
Реализуйте этот декоратор валидации, обеспечивающий безопасное и монотонное позиционирование каретки.
Что уже дано
В редакторе представлена заготовка функции-фабрики directional_steps(direction, max_step). Вспомогательная проверочная функция observe_directional_steps уже доступна в тестовом окружении, реализовывать её не требуется.
Что нужно сделать
Реализуйте фабрику декоратора directional_steps(direction, max_step).
Функция принимает два параметра:
direction(int) — разрешённое направление движения:+1(только вперёд) или-1(только назад);max_step(intилиfloat) — конечное неотрицательное число в диапазоне от0до1 000 000, задающее максимальную абсолютную величину смещения за один вызов.
Фабрика возвращает декоратор, принимающий целевую функцию двигателя motor. Декоратор возвращает функцию-обёртку, которая принимает абсолютную координату x (число в диапазоне от -1 000 000 до 1 000 000), а затем произвольные позиционные и именованные аргументы исходной функции (*args, **kwargs).
Правила проверки и фиксации перемещений:
- Для каждого задекорированного двигателя отсчёт начинается с координаты
0. Состояния разных двигателей независимы, даже если они созданы одной фабрикой. - Смещение вычисляется как разность между переданной координатой
xи последней успешно зафиксированной позицией:displacement = x - current_pos. - Перемещение отклоняется возбуждением
ValueError(или его подкласса) до вызова функции двигателя, если: - смещение равно нулю (
displacement == 0); - знак смещения не соответствует строго направлению (при
direction == 1требуетсяdisplacement > 0, а приdirection == -1требуетсяdisplacement < 0); - абсолютная величина смещения строго больше допустимой (
abs(displacement) > max_step). - Ненулевое смещение, модуль которого в точности равен
max_step, считается допустимым. - При отклонении перемещения сохранённая координата не изменяется.
- Если шаг допустим, декоратор вызывает целевую функцию двигателя ровно один раз, передавая ей исходную координату
xсо всеми переданными аргументами вызова. - Новая позиция
xфиксируется в состоянии только после успешного завершения вызова целевой функции. - Если функция двигателя возбуждает исключение, оно пробрасывается наружу как исходный объект ошибки, а сохранённая координата остаётся прежней.
- При успешном выполнении двигателя обёртка возвращает его оригинальный результат (включая
None, пустые коллекции и изменяемые объекты).
Каждая декорированная функция может последовательно вызываться от 0 до 1000 раз.
Ввод и вывод
Стандартные потоки ввода stdin и вывода stdout в решении не используются: считывать ввод и вызывать print() не нужно. После выполнения кода учащегося проверяющая система считывает из пространства имён модуля функцию верхнего уровня directional_steps и вызывает её с проверочными аргументами.
Пример использования
moves = []
@directional_steps(1, 2)
def motor(x):
moves.append(x)
return x
print(motor(2))
try:
motor(2)
except ValueError:
print('rejected')
print(motor(4))
print(moves)
Вывод:
2
rejected
4
[2, 4]
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Связанные задачи
- Functools.wraps в Python: имя функции и атрибут wrapped
- Декоратор Circuit Breaker на Python: остановка вызовов после сбоев
- Декораторы Python: проверка цепочки wrapped и метаданных функции
- Декоратор Python: логирование только медленных вызовов
- Кэширование Python: постройте ключ из выбранных аргументов функции
- Rate limiter на Python: декоратор со скользящим окном запросов
