itertools.groupby Groups Go Empty If Not Read Right Away (tested)
itertools.groupby() looks like it returns a list of groups you can read whenever you want. We measured what happens when you store the groups instead of reading them inside the loop, and the result is silent, wrong data with no exception at all.
1. Reading each group immediately works fine
import itertools
data = [("a", 1), ("a", 2), ("b", 3), ("b", 4)]
result = []
for key, group in itertools.groupby(data, key=lambda x: x[0]):
result.append((key, list(group))) # consumed right inside the loop
print(result)
[('a', [('a', 1), ('a', 2)]), ('b', [('b', 3), ('b', 4)])]
Measured: calling list(group) while the loop is still on that group produces the expected data.
2. Collecting the pairs first, then reading, silently returns empty groups
import itertools
data = [("a", 1), ("a", 2), ("b", 3), ("b", 4)]
collected = list(itertools.groupby(data, key=lambda x: x[0])) # store (key, group) pairs
for key, group in collected:
print(key, list(group))
a []
b []
Measured: both groups come back empty -- no exception, no warning, just silently wrong output. The root cause: groupby() hands out group iterators that all share the same underlying source iterator. Advancing past the first group to find the second one drains whatever was left of the first group's items, and by the time the loop body runs, every group's iterator has already been exhausted by that advancing.
3. groupby doesn't merge non-adjacent groups with the same key either
import itertools
data = [("a", 1), ("b", 2), ("a", 3)]
print([(k, list(g)) for k, g in itertools.groupby(data, key=lambda x: x[0])])
data_sorted = sorted(data, key=lambda x: x[0])
print([(k, list(g)) for k, g in itertools.groupby(data_sorted, key=lambda x: x[0])])
[('a', [('a', 1)]), ('b', [('b', 2)]), ('a', [('a', 3)])]
[('a', [('a', 1), ('a', 3)]), ('b', [('b', 2)])]
Measured: the first run produces three groups, not two -- the two 'a' rows are split apart because a 'b' row sits between them, and groupby() only ever looks at the immediately preceding key. Sorting by the key first (second run) is what actually merges them. groupby() groups consecutive items with equal keys, not all items with equal keys.
4. Fix: consume each group before moving on, and sort first if keys aren't already contiguous
import itertools
data = [("a", 1), ("b", 2), ("a", 3), ("b", 4)]
data.sort(key=lambda x: x[0]) # make equal keys contiguous
result = {key: list(group) for key, group in itertools.groupby(data, key=lambda x: x[0])}
print(result)
{'a': [('a', 1), ('a', 3)], 'b': [('b', 2), ('b', 4)]}
Measured: building the dict (or list) comprehension right inside the same loop that drives groupby() -- never deferring the list(group) call to a later loop -- keeps every group intact.
Frequently asked questions
Why do my itertools.groupby groups come back empty?
We measured this: it happens when you store the (key, group) pairs in a list or variable before reading them. All groups returned by groupby() share one underlying source iterator, so advancing to the next key drains the previous group before you ever read it.
Does groupby raise an error when this happens?
No -- we confirmed it fails silently. You get an empty list for every group with no exception, which makes it easy to miss in a script that otherwise runs cleanly.
How do I fix empty groupby groups?
Consume each group inside the same loop iteration that produced it, for example with list(group) or a dict/list comprehension, before the loop advances to the next key.
Does itertools.groupby group all matching items, even if they're not next to each other?
No -- we measured this directly: groupby() only merges consecutive items with equal keys. Equal keys separated by a different key produce separate groups; sort the data by the key first if you need all matching items together.
Is this specific to groupby, or does it affect other itertools functions?
This particular trap is specific to groupby()'s shared-iterator design per the Python docs -- it's not measured here for other itertools functions like tee() or chain(), which have their own, different gotchas.
Written with AI assistance. Measured on 2026-10-04 with Python 3.13.5's built-in itertools module: ran itertools.groupby() over a small list of (key, value) tuples, once consuming each group immediately with list(g) inside the loop, and once collecting the (key, group) pairs into a list first and reading the groups afterward. PlainHeaders is our extension; Python's itertools module is built in.