How to Combine Iterables Using itertools.chain
The itertools.chain() function in Python provides an
efficient way to treat multiple sequences as a single continuous
iterable. Instead of concatenating data structures in memory using
operators like + or unpacking syntax,
itertools.chain() traverses each provided iterable
sequentially and yields elements on demand. This article explains how
itertools.chain() works under the hood, demonstrates its
basic usage, highlights its memory benefits, and covers the alternative
chain.from_iterable() method.
How itertools.chain()
Works
The itertools.chain() function accepts zero or more
iterables as arguments (such as lists, tuples, sets, or generators) and
returns an iterator.
When iteration begins, chain() reads items from the
first iterable until it is exhausted. It then automatically advances to
the next iterable, continuing this process until all supplied iterables
have been fully consumed.
Because it operates as an iterator, elements are evaluated lazily. It does not construct an intermediate collection holding all combined items, which avoids the memory overhead of duplicating large datasets.
Basic Syntax and Example
To use chain(), import it from the built-in
itertools module and pass the iterables as positional
arguments:
from itertools import chain
list_a = [1, 2, 3]
tuple_b = ('a', 'b', 'c')
set_c = {10, 20}
combined = chain(list_a, tuple_b, set_c)
for item in combined:
print(item, end=' ')
# Output: 1 2 3 a b c 10 20Memory Efficiency vs. Concatenation
Combining collections using list addition
(list_a + list_b) or unpacking
([*list_a, *list_b]) allocates new memory to store the
merged result. For large collections, this can cause significant memory
spikes.
In contrast, itertools.chain() maintains references to
the original iterables and yields elements one at a time. The memory
footprint remains minimal and constant regardless of the number or size
of the collections being combined.
Using
chain.from_iterable()
When your input is already structured as an iterable of iterables
(such as a list of lists or a generator of streams), passing them
directly into chain() requires unpacking
(chain(*nested_list)), which forces Python to evaluate the
outer collection into memory before passing it as arguments.
To handle pre-nested iterables efficiently, use the class method
chain.from_iterable():
from itertools import chain
nested_data = [[1, 2], [3, 4], [5, 6]]
flattened = chain.from_iterable(nested_data)
print(list(flattened))
# Output: [1, 2, 3, 4, 5, 6]chain.from_iterable() lazily pulls each sub-iterable
only when needed, making it suitable for flattening streams or
generators of unknown or infinite length.