Генераторы Python: объединение закрываемых источников данных

Напишите решение на Python и проверьте его на странице.

Другие упражнения по этой теме: Генераторы Python: задачи на ленивые конвейеры и закрытие ресурсов.

Сквозной генератор сегментов архива

Потоковый считыватель архива разбирает данные по цепочке независимых файлов-сегментов, каждый из которых оформлен собственным закрываемым итератором. В начале каждой сессии источник выдаёт строковый заголовок, а следом за ним — серию числовых замеров. Задача главного генератора — принимать эти порции и отдавать потребителю сплошной плоский поток чисел.

При переходе от одного файла к следующему конвейер обязан аккуратно закрывать завершившийся итератор и проверять, что новый сегмент открылся без сбоев. В каждый момент времени открытым может оставаться только один текущий ресурс: пока данные читаются из активного файла, следующие сегменты из общего списка не должны инициироваться заранее.

Если же внешний потребитель решает прервать обработку и досрочно вызывает close(), генератор должен освободить ровно тот сегмент, на котором остановилось чтение, оставив нетронутыми все последующие нераспакованные источники. Реализуйте этот генератор сквозного чтения с безопасным поэтапным управлением файловыми ресурсами.

Что уже дано

В среде выполнения доступны вспомогательный класс ArchiveSegment и функция make_segment_chain_probe(segments) для создания фабрик сегментов. Реализовывать их заново не требуется: вам нужно написать только генераторную функцию stream_segments.

Что нужно сделать

Реализуйте функцию-генератор stream_segments(segment_factories).

Функция принимает список segment_factories (от 0 до 100 элементов), состоящий из функций без аргументов. Каждый вызов фабрики открывает новый закрываемый итератор сегмента архива: первое значение в нём — строковый заголовок сессии, а все последующие — конечные числовые значения (типы int, float, включая bool, в диапазоне от -1 000 000 до 1 000 000). Общее количество замеров во всех сегментах составляет от 0 до 1000.

Правила потоковой обработки:

  • stream_segments должен быть нативным генератором Python. До первого запроса значения через next() ни одна фабрика не должна вызываться, и ни один ресурс сегмента не должен открываться.
  • Очередной сегмент открывается строго в момент, когда генератору необходимо получить из него данные. Сразу после открытия сегмента необходимо прочитать его первый элемент — заголовок сессии — и отбросить его, не отдавая наружу.
  • Все последующие числовые замеры из текущего сегмента выдаются наружу через yield в исходном порядке.
  • Допустимы сегменты, содержащие только заголовок и ни одного замера. В этом случае генератор переходит к следующему сегменту цепочки.
  • Перед открытием следующего сегмента предыдущий сегмент должен быть гарантированно закрыт вызовом его метода close(). В любой момент времени открытым может быть не более одного сегмента.
  • При полном исчерпании всех сегментов каждый открытый сегмент должен оказаться закрытым.
  • Если потребитель досрочно закрывает сам генератор вызовом close() (в том числе до первого шага next()), генератор обязан закрыть текущий открытый сегмент (если он успел открыться) и завершить работу. Будущие фабрики из списка segment_factories при этом вызываться не должны.

Ввод и вывод

Стандартные потоки ввода stdin и вывода stdout в решении не используются: считывать ввод и вызывать print() не нужно. После выполнения кода учащегося проверяющая система считывает из пространства имён модуля функцию верхнего уровня stream_segments и вызывает её с проверочными аргументами.

Пример использования

probe = make_segment_chain_probe([[1, 2], [], [3]])
stream = stream_segments(probe.factories)
print(next(stream))
print(list(stream))
print([segment.closed for segment in probe.segments])

Вывод:

1
[2, 3]
[True, True, True]
РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Связанные задачи