Контекстный менеджер Python: временная подмена списка с восстановлением
Напишите решение на Python и проверьте его на странице.
Другие упражнения по этой теме: Контекстные менеджеры Python: задачи на with, откат и исключения.
Временный учебный канал пульта
Центральный пульт диспетчерской отправляет оперативные извещения в активный канал console.receiver. Во время учебных тревог этот поток нужно временно перехватывать, чтобы тестовые сигналы не смешивались с реальными сообщениями. Для этого вход в учебный режим подменяет рабочий список в приёмнике на отдельный чистый буфер и передаёт его для накопления записей в блок with.
При любом выходе из тренировочной сессии исходный приёмник гарантированно возвращается в console.receiver. Штатный рабочий канал и независимый внешний накопитель archive никогда не ссылаются на один и тот же список. Если тренировка прошла без ошибок, накопленные сообщения дописываются в конец archive и остаются в самом учебном буфере. Если же внутри блока произошёл сбой, выданный буфер очищается на месте вызовом clear(), в архив ничего не добавляется, а возникшая ошибка пробрасывается наружу.
Реализуйте функцию-менеджер контекста с декоратором @contextlib.contextmanager, которая изолирует учебные записи пульта во временном буфере, надёжно восстанавливает рабочий приёмник и пополняет внешний архив только при успешном завершении сессии.
Что уже дано
В заготовке уже импортирован декоратор contextmanager из модуля contextlib и объявлена заготовка функции temporary_alert_channel(console, archive). Вспомогательные классы AlertConsole, его тестовые варианты и проверочные функции observe_prepared_empty_alert, observe_alert_sessions и observe_alert_redirected_buffer уже доступны в окружении при выполнении, реализовывать их заново не требуется.
Что нужно сделать
Реализуйте генераторную функцию-менеджер контекста temporary_alert_channel(console, archive) с декоратором @contextmanager.
Функция принимает два аргумента:
console— объект пульта с перезаписываемым атрибутомreceiver(текущий рабочий списокlist[str]) и методомemit(record: str), который добавляет запись в конец текущего установленного приёмникаconsole.receiver. Требовать точный конкретный тип от пульта нельзя: важен только интерфейс;archive— внешний накопительный список строкlist[str], объект которого должен оставаться неизменным. При входе исходный приёмник пульта и архив гарантированно являются двумя разными объектами списков (их совпадение по ссылке не входит в поддерживаемые входные данные, добавлять проверку или особое исключение для этого случая не нужно).
Правила работы менеджера контекста:
- Генератор инициализируется лениво: подготовка и переключение канала происходят только при фактическом входе в блок
with. - При входе в контекст менеджер запоминает ровно тот объект приёмника, который установлен в
console.receiverв этот момент, создаёт свежий пустой список[]для учебных записей, устанавливает его вconsole.receiverи отдаёт этот же список наружу черезyield. - При любом выходе из блока
with(как успешном, так и при исключении) в атрибутconsole.receiverдолжен быть гарантированно возвращён исходный сохранённый объект приёмника по идентичности (is), с сохранением его содержимого. - При успешном выходе из блока все элементы выданного учебного буфера последовательно дописываются в конец существующего списка
archive. Сам учебный буфер при этом не очищается и не заменяется. - Если внутри блока
withвозникло любое исключение (BaseException), вarchiveничего не добавляется, выданный учебный буфер очищается на месте вызовом.clear(), а само исключение беспрепятственно распространяется дальше без подавления или подмены. - Правило принадлежности буфера: архивация при успехе и очистка при ошибке всегда применяются именно к исходно выданному учебному списку, даже если внутри тела
withатрибутconsole.receiverбыл переназначен на другой список. Подменять архив или очищать сторонний список запрещено. - Каждый вызов
temporary_alert_channelсоздаёт независимый однократный менеджер контекста с новым буфером. Учебные буферы предыдущих успешных сессий должны оставаться нетронутыми.
Объём проверочных данных: от 0 до 100 последовательных сессий, от 0 до 1000 строк в исходных списках и до 1000 строк длиной до 100 символов за одну сессию.
Ввод и вывод
Стандартные потоки ввода stdin и вывода stdout в решении не используются: считывать ввод и вызывать print() не нужно. После выполнения кода учащегося проверяющая система считывает из пространства имён модуля функцию верхнего уровня temporary_alert_channel и вызывает её с проверочными аргументами.
Пример использования
console = AlertConsole(['main'])
archive = ['old']
with temporary_alert_channel(console, archive) as training:
console.emit('test')
print(console.receiver)
print(training)
print(archive)
try:
with temporary_alert_channel(console, archive) as failed:
console.emit('discard')
raise ValueError('stop')
except ValueError:
print(failed)
print(console.receiver)
print(archive)
Вывод:
['main']
['test']
['old', 'test']
[]
['main']
['old', 'test']
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Связанные задачи
- exit в Python: аргументы исключения и подавление ошибки
- Контекстный менеджер Python: подавление выбранных типов исключений
- Контекстный менеджер Python: вложенные транзакции и глубина входа
- Контекстный менеджер Python: откат списания ресурсов при ошибке
- Проверка контекстного менеджера Python: подавление и замена исключения
- Contextmanager на Python: транзакционные изменения словаря с квотой
