Класс-декоратор Python: проверка чередования фаз вызова
Напишите решение на Python и проверьте его на странице.
Другие упражнения по этой теме: Классы-декораторы Python: задачи на call, методы и состояние.
Декоратор фаз привода
Блок управления приводом позиционирует шаговый двигатель через функцию подачи импульса. Чтобы механизм перемещался без сбоев, команды должны строго чередовать две фазы: фазу разгона 'accel' и фазу удержания 'hold'. После инициализации системы первым вызовом всегда допускается только 'accel'.
Контролировать этот порядок поручено специальному классу-декоратору. При каждом обращении он проверяет аргумент фазы: если вызывающий код нарушает последовательность (например, передаёт разгон дважды подряд), декоратор не запускает целевую функцию, а сразу возбуждает служебное исключение нарушения протокола.
Ожидание переключается на противоположную фазу только при успешном завершении шага. Если же внутри целевой функции происходит аппаратная ошибка, состояние остаётся прежним, позволяя вызывающей стороне повторить сорвавшуюся операцию. Реализуйте этот класс-декоратор конечного автомата.
Что уже дано
В редакторе объявлена заготовка класса PhaseGuard с методами __init__ и __call__.
При проверке также доступно исключение PhaseOrderError(RuntimeError), сигнализирующее об ошибке последовательности фаз. Реализовывать его самостоятельно не требуется.
Что нужно сделать
Реализуйте класс PhaseGuard:
- Конструктор
__init__(self, function)принимает синхронный вызываемый объектfunctionи сохраняет его для последующих запусков. - Метод
__call__(self, phase, *args, **kwargs)принимает название фазыphaseпервым аргументом и перенаправляет остальные позиционные и именованные параметры без изменений. - Аргумент
phaseпринимает значения'accel'или'hold'(включая пользовательские подклассы строкиstr). - При инициализации экземпляра допустимой считается исключительно фаза
'accel'. - Если значение
phaseне совпадает с ожидаемым на текущем шаге, метод обязан возбудить исключениеPhaseOrderError(или его наследника) до вызова декорируемой функции. Сама функция при этом не вызывается, а текущее состояние ожидания не меняется. - Если фаза совпадает с ожидаемой, декоратор вызывает декорируемую функцию ровно один раз, передавая
phaseи все остальные аргументы*args,**kwargsкак есть. - При успешном завершении целевой функции ожидаемая фаза переключается на противоположную (
'accel'меняется на'hold', а'hold'— на'accel'), а метод__call__возвращает результат её работы. - Если целевая функция возбуждает любое исключение (семейства
BaseException), это же исключение должно беспрепятственно всплыть выше. Ожидаемая фаза при этом не меняется и остаётся прежней. - Состояние конечного автомата изолировано для каждого экземпляра
PhaseGuard. Разные экземпляры могут независимо обрабатывать до 1000 вызовов каждый. - Реализовывать сохранение метаданных функции или логику дескриптора для методов не требуется.
Ввод и вывод
Стандартные потоки ввода stdin и вывода stdout в решении не используются: считывать ввод и вызывать print() не нужно. После выполнения кода учащегося проверяющая система считывает из пространства имён модуля класс верхнего уровня PhaseGuard и вызывает его с проверочными аргументами.
Пример использования
guard = PhaseGuard(lambda phase, value: (phase, value * 2))
print(guard('accel', 3))
try:
guard('accel', 4)
except PhaseOrderError:
print('PhaseOrderError')
print(guard('hold', 4))
Вывод:
('accel', 6)
PhaseOrderError
('hold', 8)
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Связанные задачи
- Класс-декоратор Python: когда вызывается init
- Класс-декоратор метода Python: почему теряется self
- Класс-декоратор Python: ограничение изменения результата между вызовами
- Класс-декоратор Python: баланс доступных вызовов функции
- Класс-декоратор Python: изменение аргумента первых N вызовов
- Класс-декоратор Python: буфер событий и пакетная запись
