map and filter apply a function to each item or select items, and in Python 3 they return lazy iterators. List comprehensions do the same jobs with clearer syntax, and are usually preferred. reduce folds a sequence down to a single value.
Side by side
nums = [1, 2, 3, 4, 5, 6] list(map(lambda x: x * x, nums)) # [1, 4, 9, 16, 25, 36] [x * x for x in nums] # same, as a comprehension list(filter(lambda x: x % 2 == 0, nums)) # [2, 4, 6] [x for x in nums if x % 2 == 0] # same
The comprehension reads as one expression, and needs no lambda. That is why most style guides prefer it. map is reasonable when you already have a named function: map(str.strip, lines).
Lazy, not a list
map(...) and filter(...) do not compute anything until you iterate over them. You can loop over them once, and then they are used up. Wrap with list() if you need to reuse the results. For the same laziness with comprehension syntax, use a generator expression with round brackets:
total = sum(x * x for x in range(10_000_000)) # no huge list in memory
For large data, this memory difference matters a lot.
reduce
from functools import reduce reduce(lambda acc, x: acc + x, nums, 0) # 21
reduce moved to functools in Python 3. It combines items pairwise with a function and a start value. For sums, products and joins, built-ins such as sum, math.prod and str.join are clearer and faster. It is useful for custom folds, for example merging a list of dictionaries.
Why interviewers ask
The same ideas appear in Spark: RDD map, filter and reduce take functions and run them over distributed data, and reduceByKey is a keyed fold. Understanding them in plain Python makes Spark easier.
A good summary
Use comprehensions for readability, generator expressions for large streams, and map or filter with named functions when it reads well. Use built-in aggregates before reduce.