Python itertools.batched: разбить список на части

Категория: Python · Язык: Python · Обновлено:

itertools.batched() делит iterable на кортежи заданного размера и появился в Python 3.12. Последняя группа может быть короче, а пустой вход не даёт ни одной группы. Функция работает лениво: читает элементы по мере запроса и не копирует весь список целиком.

Разбить список на группы по три

Python
from itertools import batched

items = [1, 2, 3, 4, 5, 6, 7]
chunks = list(batched(items, 3))

print(chunks)  # [(1, 2, 3), (4, 5, 6), (7,)]

Размер группы должен быть положительным целым числом. batched() возвращает кортежи, а не списки, поэтому не пытайтесь изменить группу на месте. Если нужен другой тип, преобразуйте явно: [list(chunk) for chunk in batched(items, 3)].

В отличие от нарезки items[i:i + 3], batched() принимает любой iterable, включая генератор и файловый объект. Это удобно для потоковой обработки: в памяти находится только текущая группа, а не весь набор.

Проверить аргумент и обработать ошибку

Python
from itertools import batched

try:
    list(batched([1, 2], 0))
except ValueError as exc:
    print(exc)  # n must be at least one

Нулевой или отрицательный размер вызывает ValueError при первом обращении к итератору, а не при создании объекта. Отрицательное число не означает «взять с конца». Для больших батчей учитывайте, что группа всё равно материализуется в кортеж: миллион элементов с n=1_000_000 займёт много памяти.

На Python 3.10 и 3.11 используйте рецепт с itertools.islice:

Python
from itertools import islice

def batched(iterable, n):
    iterator = iter(iterable)
    while chunk := tuple(islice(iterator, n)):
        yield chunk

Проверьте, что n > 0, если функция принимает размер из конфигурации. Для асинхронных источников itertools.batched() не подходит: он работает с обычными синхронными итераторами.

Документация: itertools.batched, рецепты itertools.