Iteration Tools with itertools
Some problems require exploring structured combinations: forming pairs, generating permutations, Cartesian products of parameter sets, or merging sequences. Doing this manually is error-prone and memory-intensive.itertools supplies a suite of combinatorial and iterative generators—functions that produce values lazily, one at a time, without materializing all output at once. Combinatorial tools may still store their finite input pools; lazy output does not make an enormous search space small.
Combinations
A combination selects items without regard to order.
Signature:
combinations(iterable, r)
Generates r-length subsets where order does not matter.
For example, forming project pairs in a group of students:
from itertools import combinations
students = ["Ada", "Grace", "Alan"]
for pair in combinations(students, 2):
print(pair)Output
('Ada', 'Grace')
('Ada', 'Alan')
('Grace', 'Alan')
This produces all unique 2-person groups—valuable in co-occurrence analysis or team formation algorithms.
Permutations
In other scenarios, the order does matter—for example, generating possible task sequences, testing input arrangements, or exploring order-sensitive models.
Permutations help enumerate every possible ordered arrangement of a collection, making them essential in optimization, simulation, and combinatorial search problems.
Signature:
permutations(iterable, r)
For instance, if we want to generate all ordered pairs from a list of letters, permutations produces each possible arrangement:
from itertools import permutations
letters = ["A", "B", "C"]
for p in permutations(letters, 2):
print(p)Output
('A', 'B')
('A', 'C')
('B', 'A')
('B', 'C')
('C', 'A')
('C', 'B')
Here each pair appears in every possible order, giving a complete view of all ordered arrangements.
Cartesian Products
Some tasks require exploring every possible combination across two or more sets. This appears frequently in machine learning (hyperparameter grids), simulation studies, scheduling problems, or combining dimensions like color × size × shape.
The product function from itertools generates these combinations efficiently and lazily—no nested loops or temporary lists needed.
Signature:
product(iter1, iter2, ...)
It returns an iterator producing tuples that contain one element from each iterable.
Example:
The code below generates every combination of learning rate and batch size:
from itertools import product
learning_rates = [0.01, 0.1]
batch_sizes = [16, 32]
for combo in product(learning_rates, batch_sizes):
print(combo)Output
(0.01, 16)
(0.01, 32)
(0.1, 16)
(0.1, 32)
product systematically pairs each learning rate with each batch size, giving all four combinations. This pattern is widely used in machine learning for hyperparameter tuning, where you try all combinations of parameter values to see which combination yields the best model performance. Using product makes such systematic exploration much easier and more scalable.
Chaining Iterables
Sometimes datasets come from different sources—multiple files, pages, or batches—but you want to iterate over all items as if they were one continuous sequence. The chain function from itertools provides exactly this: a lazy iterator that streams several iterables back-to-back without copying them.
Signature:
chain(iter1, iter2, ...)
The following code merges three lists of names into a single stream:
from itertools import chain
group1 = ["Ada", "Grace"]
group2 = ["Alan"]
group3 = ["Linus", "Margaret"]
for name in chain(group1, group2, group3):
print(name)Output
Ada
Grace
Alan
Linus
Margaret
chain yields items from each iterable in order, behaving like one long sequence. Because items are produced lazily, it scales efficiently to large datasets.