Фильтрация потока Python: исключения и гарантированное закрытие генератора
Напишите решение на Python и проверьте его на странице.
Другие упражнения по этой теме: Генераторы Python: задачи на ленивые конвейеры и закрытие ресурсов.
Шлюз очистки потока
Шлюз очистки данных принимает ленивый генератор записей и отбирает из него только те элементы, которые удовлетворяют готовому предикату схемы. Если же во входном потоке встречается специальный маркер неисправности 'CORRUPTED', шлюз сразу прерывает обработку и возбуждает исключение ValueError('corrupted stream').
При любом завершении работы — будь то штатное исчерпание записей, аварийный маркер или прямой вызов close() у самого шлюза — валидатор обязан в блоке finally вызвать close() у входящего генератора. Однако процедура очистки стороннего источника может сама завершиться ошибкой: в таком случае валидатор должен подавить вторичное исключение стороннего close(), сохраняя первичное исключение потока или нормальный выход без подмены причины.
Реализуйте генератор-валидатор, который фильтрует поток по схеме, вовремя реагирует на маркер сбоя и гарантированно закрывает исходный генератор с защитой от ошибок его финализации.
Что уже дано
В среде выполнения доступны вспомогательные фабрики источников и проверочные инструменты (например, make_validation_source), которые используются в тестах и примере. Реализовывать их заново не требуется: вам нужно написать только саму генераторную функцию validate_stream.
Что нужно сделать
Реализуйте генераторную функцию validate_stream(source, predicate).
Функция принимает два аргумента:
source— однократный итератор, содержащий от 0 до 1000 записей (числаint/floatв диапазоне от -1 000 000 до 1 000 000 или строки длиной от 0 до 100 символов, включая их обычные подклассы). Источник предоставляет методclose(), освобождающий базовый ресурс.predicate— вызываемый объект (функция), истинность результата которого определяет допуск обычной записи.
Функция должна возвращать неначатный (unstarted) нативный генератор Python со следующим поведением:
- Создание генератора не выполняет чтений из
sourceи не вызываетpredicate. Если созданный генератор закрывается вызовом методаclose()до первого запроса значения, тело генератора не начинает выполняться, а методsource.close()не вызывается. - Чтение из
sourceпроисходит строго по требованию: ровно настолько, насколько необходимо для выдачи очередного прошедшего проверку значения. Каждая подходящая запись отдаётся без изменений черезyieldс сохранением исходного порядка и дубликатов. - Если очередная запись из
sourceравна литералу'CORRUPTED'(включая строковые подклассы), генератор обязан возбудить исключениеValueError(или его подкласс) с точным сообщением'corrupted stream'ещё до вызоваpredicateи навсегда прекратить чтение. - Для обычных записей вызывается
predicate(record). Решение о пропуске принимается по логической истинности (bool(predicate(record))), не требуя строгого объектаTrue. - При любом выходе из начатого генератора (штатное исчерпание
source, маркер'CORRUPTED', сбой при чтении или в предикате, исключение со стороны вызывающего кода или закрытие активного генератора) необходимо в блокеfinallyвызватьsource.close(). - Если вызов
source.close()возбуждает любое исключение (включая подклассыBaseException), это исключение должно быть полностью подавлено, чтобы не подменять первичное исключение источника, предиката, потребителя или ошибку повреждения данных. Если завершение было штатным, подавление исключения закрытия оставляет выход нормальным. - Во время финализации запрещено выполнять
yieldили предпринимать повторные попытки чтения изsource.
Ввод и вывод
Стандартные потоки ввода stdin и вывода stdout в решении не используются: считывать ввод и вызывать print() не нужно. После выполнения кода учащегося проверяющая система считывает из пространства имён модуля функцию верхнего уровня validate_stream и вызывает её с проверочными аргументами.
Пример использования
source = make_validation_source([-1, 0, 2], close_failure='exception')
print(list(validate_stream(source, lambda value: value >= 0)))
Вывод:
[0, 2]
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Связанные задачи
- GeneratorExit и yield при close(): вопрос по генераторам Python
- Генераторы Python: синхронизация потоков после фильтрации
- Генераторы Python: разделите поток между двумя потребителями
- Исправьте остановку генераторного конвейера Python
- Генератор скользящего среднего на Python со сбросом окна
- Генераторы Python: закройте второй источник при ошибке первого
