Question

How to Split a List Into Equal-Sized Chunks in Python

pythonlistsplitchunks

Question

How can I split a Python list of any length into smaller chunks of equal size?

For example, if I have a list with an arbitrary number of items, I want to divide it into sublists where each sublist contains n items. If the list length is not perfectly divisible by n, the final chunk may contain fewer items.

Related topics often include iterating over a list in chunks and applying similar chunking logic to strings.

Short Answer

By the end of this page, you will understand how list chunking works in Python, why slicing is the most common solution, how to handle uneven final chunks, and how this pattern is used in real programs such as batching API requests, pagination, and data processing.

Concept

In Python, chunking a list means breaking one list into smaller lists of a fixed size.

For example:

numbers = [1, 2, 3, 4, 5, 6, 7]

If the chunk size is 3, the result should be:

[[1, 2, 3], [4, 5, 6], [7]]

The last chunk contains the remaining items because the list length is not always a perfect multiple of the chunk size.

This matters because real programs often need to process data in batches instead of all at once. Common reasons include:

  • sending API requests in groups
  • paginating results
  • processing large datasets safely
  • reducing memory usage in some workflows
  • grouping items for display in a user interface

The most common Python solution uses list slicing inside a loop or list comprehension. Slicing lets you take a portion of a list from one index to another.

A chunking solution usually follows this idea:

  1. start at index 0
  2. move forward by chunk_size each time
  3. slice from the current index to current index + chunk_size
  4. stop when you reach the end of the list

This is simple, readable, and works well for beginners and production code.

Mental Model

Think of a list like a long loaf of bread.

  • The full loaf is your original list.
  • The knife cuts it every n items.
  • Each slice becomes one chunk.
  • If the loaf does not divide evenly, the last piece is smaller.

So if your loaf has 10 items and you cut every 4 items, you get:

  • first slice: 4 items
  • second slice: 4 items
  • last slice: 2 items

Python slicing is the knife that makes those cuts.

Take Quiz

Syntax and Examples

The most common Python pattern is:

chunks = [my_list[i:i + size] for i in range(0, len(my_list), size)]

Example

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
size = 4

chunks = [numbers[i:i + size] for i in range(0, len(numbers), size)]
print(chunks)

Output:

[[1, 2, 3, 4], [5, 6, 7, 8], [9]]

How it works

  • range(0, len(numbers), size) generates starting indexes: 0, 4, 8
  • numbers[i:i + size] takes a slice from each starting index
  • each slice becomes one sublist in the result

Reusable function

def chunk_list(items, size):
    return [items[i:i + size] for i in range(0, len(items), size)]

values = ['a', 'b', 'c', 'd', 'e']
print(chunk_list(values, 2))

Output:

[['a', 'b'], ['c', 'd'], ['e']]

Important rule

The chunk size should be a positive integer.

# Good
chunk_list([1, 2, 3], 2)

# Bad
chunk_list([1, 2, 3], 0)

A size of 0 will cause an error because range() cannot step by zero.

Step by Step Execution

Consider this code:

items = [10, 20, 30, 40, 50, 60, 70]
size = 3

chunks = [items[i:i + size] for i in range(0, len(items), size)]
print(chunks)

Step 1: Calculate the range

range(0, len(items), size)

Since len(items) is 7 and size is 3, this becomes:

range(0, 7, 3)

This produces the indexes:

0, 3, 6

Step 2: Slice at each index

For i = 0:

items[0:3]  # [10, 20, 30]

For i = 3:

items[3:6]  # [40, 50, 60]

For i = 6:

items[6:9]  # [70]

Notice that Python slicing does not fail if the end index is beyond the list length. It simply stops at the end of the list.

Step 3: Collect all slices

The list comprehension builds:

[[10, 20, 30], [40, 50, 60], [70]]

Final output

[[10, 20, 30], [40, 50, 60], [70]]

Real World Use Cases

Chunking lists appears in many practical tasks.

Batch API requests

Some APIs limit how many items you can send at once.

user_ids = [1, 2, 3, 4, 5, 6, 7]
for batch in [user_ids[i:i + 3] for i in range(0, len(user_ids), 3)]:
    print("Send batch:", batch)

Pagination

A web app may display records 20 at a time.

products = list(range(1, 51))
pages = [products[i:i + 20] for i in range(0, len(products), 20)]

Processing files in groups

If you need to process thousands of filenames, chunking can make the work easier to manage.

files = ["a.csv", "b.csv", "c.csv", "d.csv"]
chunks = [files[i:i + 2] for i in range(0, len(files), 2)]

Building UI rows

If a screen should show 3 cards per row, chunking can group the data:

cards = ["A", "B", "C", "D", "E"]
rows = [cards[i:i + 3] for i in range(0, len(cards), 3)]
Take Quiz

Real Codebase Usage

In real codebases, developers usually wrap chunking logic in a function so it can be reused and validated.

Common helper function

def chunk_list(items, size):
    if size <= 0:
        raise ValueError("size must be greater than 0")
    return [items[i:i + size] for i in range(0, len(items), size)]

This adds a guard clause to reject invalid input early.

Validation pattern

Developers often validate arguments before processing:

def send_batches(items, batch_size):
    if batch_size <= 0:
        raise ValueError("batch_size must be positive")

    for i in range(0, len(items), batch_size):
        batch = items[i:i + batch_size]
        print("Processing", batch)

Streaming vs building a full list

In some projects, developers prefer a generator when the input is large:

def chunk_generator(items, size):
    if size <= 0:
        raise ValueError("size must be greater than 0")
    for i in range(0, len(items), size):
        yield items[i:i + size]

This yields one chunk at a time instead of creating the whole result list immediately.

Common patterns around chunking

  • guard clauses for invalid chunk sizes
  • early returns when the list is empty
  • batch processing loops for APIs or database work
  • configuration values such as BATCH_SIZE = 100
  • error handling when external systems reject oversized batches

Common Mistakes

Using a chunk size of 0

Broken code:

items = [1, 2, 3]
size = 0
chunks = [items[i:i + size] for i in range(0, len(items), size)]

This raises an error because range() cannot use a step of 0.

Avoid it by validating the size:

if size <= 0:
    raise ValueError("size must be greater than 0")

Forgetting that the last chunk may be smaller

Broken assumption:

items = [1, 2, 3, 4, 5]
size = 2
chunks = [items[i:i + size] for i in range(0, len(items), size)]

for chunk in chunks:
    print(chunk[1])

This fails on the last chunk if it has only one item.

Avoid it by checking length or designing your code to allow a shorter final chunk.

Using the wrong range step

Broken code:

items = [1, 2, 3, 4, 5, 6]
size = 2
chunks = [items[i:i + size] for i in range(0, len(items))]

This creates overlapping slices because the loop moves by 1, not by size.

Correct version:

chunks = [items[i:i + size] for i in range(0, len(items), size)]

Confusing flattening with chunking

Chunking creates nested lists:

[[1, 2], [3, 4], [5]]

It does not keep a flat list.

Expecting slicing to raise an error when the end index is too large

Python slicing is safe here:

items = [1, 2, 3]
print(items[2:10])  # [3]

This behavior is one reason chunking with slices works so well.

Comparisons

ApproachResult typeBest forNotes
List slicing with list comprehensionList of listsSimple chunkingMost common and readable
for loop with slicingList of listsBeginners, debuggingEasier to trace step by step
Generator with yieldIterator of chunksLarge inputsMore memory-friendly
Manual item-by-item groupingCustomSpecial rulesMore code, useful for unusual logic

List comprehension vs loop

# List comprehension
chunks = [items[i:i + size] for i in range(0, len(items), size)]
# For loop
chunks = []
for i in range(0, len(items), size):
    chunks.append(items[i:i + size])

Both are correct. The loop version is often easier for beginners to understand.

List of chunks vs generator

def chunk_generator(items, size):
    for i in range(0, len(items), size):
        yield items[i:i + size]

Use a generator when:

  • the input is large
  • you want to process one chunk at a time
  • you do not need all chunks stored at once
Take Quiz

Cheat Sheet

Basic chunking

chunks = [items[i:i + size] for i in range(0, len(items), size)]

Reusable function

def chunk_list(items, size):
    if size <= 0:
        raise ValueError("size must be greater than 0")
    return [items[i:i + size] for i in range(0, len(items), size)]

Generator version

def chunk_generator(items, size):
    if size <= 0:
        raise ValueError("size must be greater than 0")
    for i in range(0, len(items), size):
        yield items[i:i + size]

Key rules

  • size must be greater than 0
  • the last chunk may be smaller
  • slicing past the end of a list is safe in Python
  • use range(0, len(items), size) to jump by chunk size

Common pattern

for i in range(0, len(items), size):
    chunk = items[i:i + size]
    print(chunk)

Example

items = [1, 2, 3, 4, 5]
size = 2
# Result: [[1, 2], [3, 4], [5]]

FAQ

How do I split a Python list into chunks of size n?

Use slicing with a step in range():

[items[i:i + n] for i in range(0, len(items), n)]

What happens if the list length is not divisible by the chunk size?

The final chunk will contain the remaining items and may be smaller than the others.

Can I chunk a list without using a list comprehension?

Yes. You can use a regular for loop and append each slice to a result list.

Why does Python slicing work even when the end index is too large?

Python slices stop safely at the end of the list instead of raising an error.

Should I use a generator instead of returning a list?

Use a generator when you want to process chunks one at a time or reduce memory usage for large inputs.

Can I use the same idea for strings?

Yes. Strings also support slicing, so the same pattern works, but the result will be chunks of strings instead of lists.

What error happens if the chunk size is 0?

You will get an error from range() because its step cannot be zero.

Take Quiz

Mini Project

Description

Build a small batching utility for processing email recipients. In real applications, you often cannot send thousands of records in one operation, so you split the data into smaller groups. This project demonstrates list chunking, validation, and iteration over each batch.

Goal

Create a Python function that splits a list of email addresses into fixed-size batches and prints each batch for processing.

Requirements

  1. Create a function that accepts a list of email addresses and a batch size.
  2. Validate that the batch size is greater than 0.
  3. Return the email addresses as a list of chunks.
  4. Print each chunk with its batch number.
  5. Allow the final batch to contain fewer items if needed.
Take Quiz

Keep learning

Related questions

View more