← Назад к списку
ПрограммированиеPythonJunior

Напишите функцию chunked(iterable, size), которая разбивает любой итерируемый объект на части по size элементов.

Короткий ответ

  • Решение — генератор: лениво отдаёт списки по size элементов
  • Должно работать с любым iterable, не только списком
  • iter() + islice накапливают очередную порцию
  • Последняя порция может быть короче size
  • Нельзя использовать срезы — у генераторов их нет
  • В 3.12+ есть готовый itertools.batched

Корректное решение берёт итератор от входа и лениво отдаёт порции через islice, работая с любыми iterable и неполной последней порцией.

Как сказать вслух

пример ответа

Важно, что на вход может прийти не список, а любой итерируемый объект — генератор или файл, у которых нет срезов и длины. Поэтому я беру от входа итератор и в цикле набираю из него порцию через islice: получилась пустая — выходим, иначе отдаю её через yield. Так функция работает лениво и с бесконечными источниками. В свежих версиях Python есть готовый itertools.batched, и я бы об этом сказал.

Подробный ответ

Основной ответ

Наивное решение через срезы lst[i:i+size] работает только с последовательностями: у генератора, файла или сокет-стрима нет ни len(), ни срезов. Универсальный подход: получить единый итератор it = iter(iterable) и в бесконечном цикле собирать chunk = list(islice(it, size)); пустой chunk означает исчерпание — return, иначе yield chunk. Ключевой нюанс — iter() вызывается один раз: islice каждый раз продолжает с места остановки того же итератора. Решение ленивое (порция создаётся по запросу), память O(size), подходит для бесконечных потоков. Стоит валидировать size >= 1 (иначе вечный цикл) и знать стандартные аналоги: itertools.batched (Python 3.12+, отдаёт кортежи) и more_itertools.chunked.

Ключевые моменты

  • Один итератор. iter() до цикла — обязательное условие: каждый islice продолжает чтение, а не начинает сначала.
  • Ленивость. Генератор не материализует весь вход, поэтому справится с файлом на гигабайты и бесконечным потоком.
  • Краевые случаи. Пустой вход — ноль порций; длина не кратна size — короткий хвост; size <= 0 — ValueError.
  • Стандартная библиотека. itertools.batched в 3.12+ решает задачу из коробки; упоминание показывает актуальность знаний.

Практический контекст

Задача проверяет сразу протокол итераторов, генераторы и внимание к краевым случаям — поэтому её любят на секциях по Python. В работе паттерн встречается постоянно: пакетная вставка в БД по 1000 строк, отправка сообщений в API с лимитом на размер батча, обработка больших файлов.

Пример кода

from itertools import islice

def chunked(iterable, size):
    if size < 1:
        raise ValueError("size must be >= 1")
    it = iter(iterable)
    while True:
        chunk = list(islice(it, size))
        if not chunk:
            return
        yield chunk

print(list(chunked(range(7), 3)))  # [[0,1,2], [3,4,5], [6]]
print(list(chunked((x for x in "abcd"), 2)))  # [['a','b'], ['c','d']]

Частые ошибки

  • Решают через срезы и len(), ломаясь на генераторах
  • Вызывают iter() внутри цикла и бесконечно читают одну и ту же первую порцию
  • Не обрабатывают size <= 0 и получают бесконечный цикл пустых порций

ИП Кочкин Алексей Сергеевич · ИНН 390509026279 · ОГРНИП 325390000030973 · jiniys2005@yandex.ru