itertools.starmap() vs map(): The Confusing Missing-Argument Error (tested)
You have a list of argument pairs, like [(2, 3), (4, 5)], and want to call a two-argument function on each pair. Reaching for map() first feels natural. We measured what actually happens, and the error message doesn't point you anywhere near the real problem.
1. map() on a list of tuples fails with an error that never mentions tuples
import itertools
data = [(1, 2), (3, 4), (5, 6)]
print(list(map(pow, data)))
TypeError: pow() missing required argument 'exp' (pos 2)
Measured: map(func, iterable) calls func once per item in iterable -- it does not unpack tuples into separate arguments. So each call is really pow((1, 2)), one positional argument, and pow() complains that its second required argument is missing. The error says nothing about tuples or unpacking, which sends you looking in the wrong place if you don't already know this distinction exists.
2. itertools.starmap() unpacks each tuple into separate positional arguments
import itertools
data = [(1, 2), (3, 4), (5, 6)]
print(list(itertools.starmap(pow, data)))
# map() DOES work if you pass the arguments as separate iterables instead:
print(list(map(pow, [1, 3, 5], [2, 4, 6])))
[1, 81, 15625]
[1, 81, 15625]
Measured: starmap(func, iterable_of_tuples) calls func(*tuple) for each tuple, giving the same result as calling map() with the arguments already split into parallel lists. Both are valid, but starmap() is the one to use when your data already arrives pre-paired, e.g. rows from a CSV, zipped coordinates, or precomputed argument tuples -- re-splitting them into parallel lists just to use map() is extra, unnecessary work.
3. starmap() works lazily on infinite iterators, same as map()
import itertools
counter = itertools.count(1)
pairs = zip(counter, itertools.repeat(10))
sm = itertools.starmap(pow, pairs)
print(list(itertools.islice(sm, 5)))
[1, 1024, 59049, 1048576, 9765625]
Measured: pairing an infinite count() with a constant via zip() and feeding that into starmap() works fine -- it only pulls as many tuples as islice() actually asks for. starmap() is just as lazy as map(); nothing about the tuple-unpacking changes that.
Frequently asked questions
Why does map(pow, list_of_tuples) say 'missing required argument'?
We measured this: map() calls the function once per item without unpacking, so each tuple is passed as a single positional argument. pow() then complains its second argument is missing -- the error never mentions tuples, which is what makes it confusing.
What's the fix for calling a function on a list of argument tuples?
Use itertools.starmap(func, iterable_of_tuples). We confirmed it calls func(*tuple) for each tuple, giving the same result as manually unpacking.
Does map() ever unpack tuples automatically?
No -- we confirmed map() never unpacks. The only way to get the same result with map() is to pass the arguments as separate parallel iterables instead of pre-paired tuples, e.g. map(pow, xs, ys).
Is itertools.starmap() lazy like map()?
Yes -- we measured it against an infinite itertools.count() source zipped with a constant, and it only evaluated as many tuples as islice() requested.
When should I use starmap() instead of map()?
Use starmap() whenever your data already comes as an iterable of argument tuples -- CSV rows, zipped pairs, precomputed argument sets -- so you don't have to re-split it into parallel lists just to use map().
Written with AI assistance. Measured on 2026-10-04 with Python 3.13.5's built-in itertools module: called map() and itertools.starmap() on the same list of 2-tuples with pow() as the function, then confirmed starmap() also works lazily against an infinite iterator. PlainHeaders is our extension; Python's itertools module is built in.