Python itertools.batched() groups values from an iterable into tuples of a chosen maximum size. It returns batches lazily, so you can process a large input without first copying every item into a list.
The function joined the standard library in Python 3.12. Python 3.13 added the optional strict argument, which lets you reject an incomplete final batch. This small tool works well for database writes, API requests, reports, file processing, and other tasks that accept a limited number of items at once.
How itertools.batched() Works
batched() reads only enough values to build the next tuple. Each tuple contains up to n items. When fewer than n values remain, the function returns a shorter final tuple unless strict mode is enabled.
| Behavior | Result |
|---|---|
| Input divides evenly by n | Every tuple has n items |
| Items remain at the end | The final tuple is shorter |
| strict is true and the final tuple is short | ValueError is raised |
batched() Syntax
Syntax:
from itertools import batched
# strict is available in Python 3.13 and later.
batches = batched(iterable, n, strict=False)
- iterable supplies the input values.
- n sets the maximum number of values in each tuple and must be at least 1.
- strict rejects a short final batch when set to true.
The function returns an iterator of tuples. It does not return a list, and it does not pad the last tuple.
Create Fixed-Size Batches
This example groups five customer names into batches of two. The last batch contains the one remaining name.
Example:
from itertools import batched
orders = ["Asha", "Noah", "Emily", "Kabir", "Olivia"]
# Process at most two customer names in each batch.
for batch_number, customer_batch in enumerate(batched(orders, 2), start=1):
print(f"Batch {batch_number}: {', '.join(customer_batch)}")
Output:
Batch 1: Asha, Noah
Batch 2: Emily, Kabir
Batch 3: Olivia
Understand Lazy Processing
Because batched() is lazy, it can work with a generator or another one-pass iterator. It requests values only when your loop asks for the next batch. This controls memory use and lets processing begin before the source finishes producing every value.
Example:
def invoice_numbers(limit):
for number in range(1, limit + 1):
# Produce one value only when the iterator requests it.
yield f"INV-{number:03d}"
for invoice_batch in batched(invoice_numbers(5), 3):
print(invoice_batch)
Output:
('INV-001', 'INV-002', 'INV-003')
('INV-004', 'INV-005')
Note: The returned iterator is consumed once. If you need to repeat the batches, recreate it from a reusable source.
Require Complete Batches with strict
Use strict=True when every operation requires exactly n items. Python raises ValueError if the final batch is incomplete. This argument requires Python 3.13 or later.
Example:
from itertools import batched
seat_numbers = [1, 2, 3, 4, 5]
try:
# Require complete pairs of seat numbers.
for seat_pair in batched(seat_numbers, 2, strict=True):
print(seat_pair)
except ValueError as error:
print(error)
Output:
(1, 2)
(3, 4)
batched(): incomplete batch
Process Records in API-Sized Groups
Many services limit the number of records accepted by one request. You can place the call inside the loop so each tuple becomes one request payload.
Example:
from itertools import batched
product_ids = range(1001, 1011)
for id_batch in batched(product_ids, 4):
# Convert the tuple only if the client library requires a list.
payload = {"product_ids": list(id_batch)}
print("Sending:", payload)
The batches contain four, four, and two identifiers. In production, place retry and error-handling logic around each API call so one failed group does not hide which records need attention.
Common Errors
- Passing zero or a negative batch size raises ValueError.
- Expecting lists can cause type assumptions; batched() yields tuples.
- Using strict on Python 3.12 raises TypeError because that version does not support the argument.
- Converting all batches to a list removes the memory benefit of lazy iteration.
batched() and Manual Slicing
| Approach | Best fit |
|---|---|
| itertools.batched() | Any iterable, including generators and streams |
| Sequence slicing | A list or tuple that already supports indexes |
Choose batched() when you want a standard, readable operation that does not require the source to support length or slicing.
Conclusion
itertools.batched() divides iterable data into small tuples while keeping processing lazy. You can accept a short final tuple, require full batches with strict mode, and feed each group to an API, database, or reporting step. Check your Python version before using strict, and keep the iterator lazy when memory efficiency matters.