If you have a list of lists in Python, like sales from several stores, and you need one flat list, you can flatten it with a nested list comprehension: [x for row in rows for x in row]. itertools.chain does the same job.
Where people get stuck is the shape of the data. That one-liner only goes one level deep, so lists inside lists, or a mix of numbers and lists, need a different approach.
In this article, I’ll show you five ways to flatten a list, when each one makes sense, and the traps to avoid. I ran every snippet on Python 3.12.5 and NumPy 2.5.3.
The sample list of lists we’ll flatten
Before the methods, here’s the data. It’s this week’s sales from four stores, one inner list per store:
sales = [
[1250.50, 980.25, 1120.75], # Austin
[640.00, 1499.99], # Denver
[], # Boise (opened this week, no sales yet)
[310.00, 875.40], # Tampa
]
- Austin has three sales and Denver has two
- Boise opened this week, so its list is empty
- Tampa has two sales
- Seven sales in total, worth $6,676.89
The empty Boise list matters: a good flatten method should just skip it. Later I’ll add a messier export with deeper nesting. If you need to build lists like this first, see initializing a 2D list in Python.
Method 1: Flatten a list of lists with a list comprehension (Recommended)
This is the method I use most. It’s one line, it’s fast, and it reads like the two loops it replaces.
Here’s the code, using the four stores from above:
sales = [
[1250.50, 980.25, 1120.75], # Austin
[640.00, 1499.99], # Denver
[], # Boise (opened this week, no sales yet)
[310.00, 875.40], # Tampa
]
flat = [amount for store in sales for amount in store]
print(flat)
print(f"{len(flat)} sales, total ${sum(flat):,.2f}")
Output:
[1250.5, 980.25, 1120.75, 640.0, 1499.99, 310.0, 875.4]
7 sales, total $6,676.89
That gives all seven sales in one list, and the total comes to $6,676.89.

How does this code work?
Read the comprehension left to right. for store in sales visits each inner list: Austin, Denver, Boise, then Tampa.
for amount in store then visits every sale inside that store, and the amount at the front is what gets kept.
Boise’s list is empty (its length is 0, as in finding the size of a list), so the inner loop runs zero times and nothing is added.
So here’s the catch: the order of the two for clauses matters, outer list first. If nested loops are new to you, start with for i in range in Python.
Method 2: Flatten a list with itertools.chain
itertools.chain.from_iterable() walks through each inner list in turn. It’s handy for big data because it doesn’t build anything until you ask for items.
Same four stores here. Let me show you how it works:
sales = [
[1250.50, 980.25, 1120.75], # Austin
[640.00, 1499.99], # Denver
[], # Boise (opened this week, no sales yet)
[310.00, 875.40], # Tampa
]
from itertools import chain
flat = list(chain.from_iterable(sales))
print(flat)
lazy = chain.from_iterable(sales) # nothing is copied yet
print(next(lazy), next(lazy)) # pulls the first two Austin sales on demand
Output:
[1250.5, 980.25, 1120.75, 640.0, 1499.99, 310.0, 875.4]
1250.5 980.25
How does this code work?
chain.from_iterable(sales) creates an iterator that hands out Austin’s sales, then Denver’s, skips the empty Boise list, then Tampa’s.
Wrapping it in list() collects everything. Calling next() instead pulls items one at a time, which is why the second line prints just the first two Austin sales.
Pro Tip: You’ll also see chain(*sales). It works, but it unpacks every inner list as a separate argument first, so I stick with from_iterable. Loops over the result are covered in iterating through tuples in Python.
Method 3: Flatten with sum() and an empty list (and why it’s slow)
You’ll find sum(sales, []) in a lot of older answers. It works on our small list, but it gets very slow as the data grows.
Here’s the code, plus a timing test on 10,000 small lists:
sales = [
[1250.50, 980.25, 1120.75], # Austin
[640.00, 1499.99], # Denver
[], # Boise (opened this week, no sales yet)
[310.00, 875.40], # Tampa
]
import timeit
from itertools import chain
print(sum(sales, []))
big = [[i, i + 1, i + 2] for i in range(0, 30_000, 3)] # 10,000 small lists
for label, fn in [("comprehension", lambda: [x for row in big for x in row]),
("chain", lambda: list(chain.from_iterable(big))),
("sum(big, [])", lambda: sum(big, []))]:
t = min(timeit.repeat(fn, number=5, repeat=3)) / 5
print(f"{label:<14} {t * 1000:9.2f} ms")
Output:
[1250.5, 980.25, 1120.75, 640.0, 1499.99, 310.0, 875.4]
comprehension 0.63 ms
chain 0.49 ms
sum(big, []) 382.47 ms

How does this code work?
sum() normally adds numbers. Starting from an empty list, it adds lists instead: [] + Austin + Denver + Boise + Tampa.
The problem is that every + builds a brand-new list and copies everything so far. With thousands of inner lists, that copying grows with the square of the size.
So use it for a quick experiment at most. For joining just two sequences, plain + is fine, as shown in concatenating tuples in Python.
Method 4: Flatten a deeply nested list of any depth
Real exports aren’t always neat. This one has lists inside lists, a lone sale that isn’t in a list, and an empty list, all for the same seven sales:
export = [[1250.50, [980.25, 1120.75]], 640.00, [[1499.99]], [], [310.00, 875.40]] # messy export
try:
print([x for row in export for x in row])
except TypeError as err:
print("TypeError:", err)
def flatten(items):
for item in items:
if isinstance(item, (list, tuple)):
yield from flatten(item)
else:
yield item
flat = list(flatten(export))
print(flat)
print(f"{len(flat)} sales, total ${sum(flat):,.2f}")
Output:
TypeError: 'float' object is not iterable
[1250.5, 980.25, 1120.75, 640.0, 1499.99, 310.0, 875.4]
7 sales, total $6,676.89

How does this code work?
The comprehension from Method 1 expects every item to be a list. When it reaches the bare 640.00, it tries to loop over a number and raises the TypeError.
The flatten() generator checks each item. If it’s a list or tuple, yield from calls flatten() on it again and passes its values up; otherwise it yields the value itself.
That’s why depth doesn’t matter. Strings count as single values too, so they aren’t split into letters. Recursion itself is explained in recursion in Python.
Method 5: Flatten a list of lists with NumPy
If the values are numbers, NumPy can flatten too. But our stores have different numbers of sales, and that matters here:
sales = [
[1250.50, 980.25, 1120.75], # Austin
[640.00, 1499.99], # Denver
[], # Boise (opened this week, no sales yet)
[310.00, 875.40], # Tampa
]
import numpy as np
try:
np.array(sales).ravel()
except ValueError as err:
print("ValueError:", str(err).split(".")[0])
print(np.concatenate(sales))
print(np.array([[1, 2, 3], [4, 5, 6]]).ravel()) # even rows are fine
Output:
ValueError: setting an array element with a sequence
[1250.5 980.25 1120.75 640. 1499.99 310. 875.4 ]
[1 2 3 4 5 6]

How does this code work?
np.array(sales) tries to build a grid, which needs every row to be the same length. Austin has three sales, Denver two and Boise none, so it raises a ValueError.
np.concatenate() never builds the grid; it just joins the rows end to end. For rows of equal length, ravel() is the usual choice. More on arrays in converting a list to an array in Python.
Picking the right way to flatten a list
| Method | Depth | Use it when |
|---|---|---|
| List comprehension | One level | Almost always; clear and fast |
itertools.chain.from_iterable | One level | Big data, or you only need to loop once |
sum(lists, []) | One level | Never on real data (slow) |
Recursive flatten() | Any depth | Messy or mixed nesting |
np.concatenate / ravel | One level | Numeric data already in NumPy |
If you only need to combine two lists rather than flatten many, merging them is simpler, as in merging two lists without duplicates.
Things to Keep in Mind When Flattening Lists
- One-level methods only flatten one level. A list inside a list inside a list stays nested; use the recursive generator.
- A bare value mixed in with lists breaks the comprehension and chain with “object is not iterable”. Use the recursive version, or wrap the value in a list first.
- Strings are iterable. Without the
isinstancecheck, a recursive flatten would split “Austin” into letters. - Empty inner lists are skipped by every method, so no clean-up is needed for stores with no sales.
Nested data shows up everywhere, so these guides are worth a look too:
- Convert a dictionary to a list in Python
- Remove duplicates from a list in Python
- Sort a list of lists in Python
- Get unique values from a list in Python
Frequently asked questions
How do I flatten a list of lists in Python?
Use [x for row in rows for x in row], or list(itertools.chain.from_iterable(rows)).
What is the fastest way to flatten a list?
A list comprehension or itertools.chain. Avoid sum(rows, []) on anything but tiny lists.
How do I flatten a list nested several levels deep?
Use a recursive generator that yields from sublists and yields other items as they are.
Why do I get ‘object is not iterable’ when flattening?
Some items aren’t lists. One-level methods expect every item to be iterable; use a recursive flatten for mixed data.
Can NumPy flatten a list of lists?
Yes: np.concatenate(rows) for uneven rows, or np.array(rows).ravel() when every row is the same length.
Where is itertools.chain documented?
See itertools.chain.from_iterable() in the Python docs.

Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn