Python
map function
programming
functional programming
coding tips

How to do multiple arguments to map function where one remains the same

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Python's map() applies a function to each element of an iterable. When the function takes multiple arguments and one should stay constant across all calls, you need a way to "fix" that argument. The main approaches are functools.partial(), lambda wrappers, list comprehensions, and itertools.starmap(). Each has trade-offs in readability and performance, but functools.partial and list comprehensions are the most common choices.

The Problem

python
1def multiply(x, factor):
2    return x * factor
3
4numbers = [1, 2, 3, 4, 5]
5
6# This fails — map passes only one argument per call
7# map(multiply, numbers)  # TypeError: multiply() missing 1 required argument
8
9# We want: multiply(1, 10), multiply(2, 10), multiply(3, 10), ...

map(func, iterable) calls func(item) for each item. If func requires two arguments and one is always the same, you need to bind that constant argument.

python
1from functools import partial
2
3def multiply(x, factor):
4    return x * factor
5
6numbers = [1, 2, 3, 4, 5]
7
8# Fix 'factor' to 10
9multiply_by_10 = partial(multiply, factor=10)
10result = list(map(multiply_by_10, numbers))
11print(result)  # [10, 20, 30, 40, 50]
12
13# Or inline
14result = list(map(partial(multiply, factor=10), numbers))

partial(func, **kwargs) creates a new function with some arguments pre-filled. It is the cleanest approach for fixing one or more arguments while letting map() supply the rest.

Solution 2: Lambda Wrapper

python
1def power(base, exponent):
2    return base ** exponent
3
4numbers = [1, 2, 3, 4, 5]
5
6# Fix exponent to 3
7cubes = list(map(lambda x: power(x, 3), numbers))
8print(cubes)  # [1, 8, 27, 64, 125]
9
10# Multiple fixed arguments
11def format_value(value, prefix, suffix):
12    return f"{prefix}{value}{suffix}"
13
14formatted = list(map(lambda v: format_value(v, "$", ".00"), [10, 20, 30]))
15print(formatted)  # ['$10.00', '$20.00', '$30.00']

A lambda wrapping the function call is the most flexible approach. It works with any argument pattern but is less reusable than partial since the lambda is typically defined inline.

Solution 3: List Comprehension (Most Pythonic)

python
1def multiply(x, factor):
2    return x * factor
3
4numbers = [1, 2, 3, 4, 5]
5
6# List comprehension — often clearer than map + lambda
7result = [multiply(x, 10) for x in numbers]
8print(result)  # [10, 20, 30, 40, 50]
9
10# With conditional filtering
11result = [multiply(x, 10) for x in numbers if x > 2]
12print(result)  # [30, 40, 50]

List comprehensions are generally preferred over map() with lambda in Python because they are more readable and support filtering. The Python community considers them more idiomatic than functional-style map() calls.

Solution 4: itertools.repeat with map

python
1from itertools import repeat
2
3def multiply(x, factor):
4    return x * factor
5
6numbers = [1, 2, 3, 4, 5]
7
8# map with two iterables — repeat provides the constant
9result = list(map(multiply, numbers, repeat(10)))
10print(result)  # [10, 20, 30, 40, 50]

map() can take multiple iterables when the function takes multiple positional arguments. itertools.repeat(value) creates an infinite iterator that yields the constant value. map() stops when the shortest iterable is exhausted.

Solution 5: itertools.starmap

python
1from itertools import starmap, repeat
2
3def power(base, exponent):
4    return base ** exponent
5
6# Create pairs of (base, exponent) where exponent is constant
7pairs = zip([2, 3, 4, 5], repeat(3))
8result = list(starmap(power, pairs))
9print(result)  # [8, 27, 64, 125]
10
11# Or with pre-built tuples
12data = [(2, 3), (3, 3), (4, 3), (5, 3)]
13result = list(starmap(power, data))
14print(result)  # [8, 27, 64, 125]

starmap() unpacks each tuple from the iterable as arguments to the function. It is useful when your data is already in tuple form or when combining multiple iterables with zip.

Solution 6: operator Module for Built-in Operations

python
1from operator import mul
2from functools import partial
3
4numbers = [1, 2, 3, 4, 5]
5
6# operator.mul is faster than a custom function
7result = list(map(partial(mul, 10), numbers))
8print(result)  # [10, 20, 30, 40, 50]
9
10# Note: partial(mul, 10) creates mul(10, x), not mul(x, 10)
11# For commutative operations like mul this doesn't matter

The operator module provides function versions of Python operators. They are implemented in C and faster than equivalent lambda functions for simple arithmetic.

Performance Comparison

python
1import timeit
2from functools import partial
3from itertools import repeat
4
5def multiply(x, factor):
6    return x * factor
7
8numbers = list(range(10000))
9
10# List comprehension
11t1 = timeit.timeit(lambda: [multiply(x, 10) for x in numbers], number=1000)
12
13# map + partial
14t2 = timeit.timeit(lambda: list(map(partial(multiply, factor=10), numbers)), number=1000)
15
16# map + lambda
17t3 = timeit.timeit(lambda: list(map(lambda x: multiply(x, 10), numbers)), number=1000)
18
19# map + repeat
20t4 = timeit.timeit(lambda: list(map(multiply, numbers, repeat(10))), number=1000)
21
22print(f"Comprehension: {t1:.3f}s")
23print(f"map + partial:  {t2:.3f}s")
24print(f"map + lambda:   {t3:.3f}s")
25print(f"map + repeat:   {t4:.3f}s")

Performance differences are small for most use cases. map + repeat is typically fastest because it avoids creating a wrapper function. List comprehensions and map + partial are close. Choose based on readability.

Common Pitfalls

  • partial binds positional arguments from the left: partial(func, 10) fixes the first argument. If you need to fix the second argument, use keyword arguments: partial(func, factor=10). If the function does not accept keyword arguments, use a lambda.
  • Lambda variable capture in loops: map(lambda x: x * factor, items) captures factor by reference. If factor changes after the lambda is created, the lambda uses the new value. Bind it explicitly: lambda x, f=factor: x * f.
  • Forgetting list() around map(): In Python 3, map() returns a lazy iterator. You must call list() to materialize the results or iterate over them. Printing map(...) directly shows <map object>, not the values.
  • Using map + lambda when a comprehension is clearer: list(map(lambda x: x * 10, items)) is less readable than [x * 10 for x in items]. Prefer comprehensions when the transformation is simple.
  • repeat() without map(): itertools.repeat(10) creates an infinite iterator. If used outside map() or zip(), it runs forever. Always consume it through a function that stops at the shorter iterable.

Summary

  • Use functools.partial(func, constant_arg) to fix arguments for map()
  • Use a lambda wrapper for flexible argument binding: map(lambda x: func(x, constant), items)
  • Prefer list comprehensions over map + lambda for readability
  • Use itertools.repeat() with map() to provide a constant as a second iterable
  • Use itertools.starmap() when data is already in tuple form
  • partial binds from the left — use keyword arguments to fix non-first parameters

Course illustration
Course illustration

All Rights Reserved.