62

Is there any way to map list items to a function along with arguments?

I have a list:

pages = [p1, p2, p3, p4, p5...]

And I have to call function myFunc corresponding to each list elements along with additional arguments such that the following can be computed

myFunc(p1, additionalArgument)
myFunc(p2, additionalArgument)

and so on...

Is there any elegant method for doing this?

Sushant Gupta
  • 8,980
  • 5
  • 43
  • 48
  • 1
    possible duplicate of [Using Python map() function with keyword arguments](http://stackoverflow.com/questions/13499824/using-python-map-function-with-keyword-arguments) – LondonRob Nov 12 '14 at 13:52
  • 3
    @LondonRob The question was asked before the one you provided link for. – Sushant Gupta Nov 12 '14 at 13:53

4 Answers4

128

You can also use a lambda function:

map(lambda p: myFunc(p, additionalArgument), pages)
amarchiori
  • 1,329
  • 1
  • 8
  • 3
  • why is using map(lambda p: myFunc(p, additionalArgument), pages) superior to [myFunc(p, additionalArgument) for p in pages]? I'd suggest that this is only the case for very simple functions. Would gladly accept comments as I am new to python – OldSchool Mar 16 '20 at 14:31
  • @OldSchool Most people consider list comprehensions to be more idiomatic in Python than using `map()`. Guido even wanted to remove `map()` from the language at some point. However, the community decided to keep it, so it's definitely fine to use if you prefer it. I personally often use it when mapping an existing function over an iterable, but I'd never use `map(lambda:..., ...)`, since this really has no advantage over a list comprehension, and is even slower due to the added function call overhead. – Sven Marnach Mar 17 '20 at 09:24
  • @Sven, thanks. Makes sense. Leaving `map()` aside, is there any reason to write `[lambda p: myFunc(p, additionalArgument) for p in pages]` rather than just `[myFunc(p,additionalArgument) for p in pages]`? – OldSchool Mar 20 '20 at 09:30
  • @OldSchool Sure, you can write that if you want a list of lambda functions. Note that these lambda funcitons will just be created and stored in the list. They won't be called by the list comprehension. It is unclear to me what you are trying ot achieve. – Sven Marnach Mar 20 '20 at 09:32
  • @Sven. What I am trying to say is that I don't see the benefit of using the `lambda` keyword if the lambda is just calling `myFunc()`. Might as well just put `myFunc()` in there without wrapping it in a lambda no? – OldSchool Mar 20 '20 at 09:36
  • @OldSchool You suggested the lambda. I don't think it makes sense to add it to the list comprehension, since you will end up with a list of identical lambda functions that haven't been called. The expression `f(x)` calls the function `f` with arg `x`. The expression `lambda x: f(x)` creates a new lambda function object that can be called later. – Sven Marnach Mar 20 '20 at 09:45
  • list comprehension is nice, but I consider this is better, as it can be applied to some operations over an array using vectorization and numpy. Let's imagine this example could be applied to an array: np.array(map(lambda p: myFunc(p, additionalArgument), pages)) – xCovelus Jun 19 '22 at 21:49
83

Use a list comprehension:

result = [myFunc(p, additionalArgument) for p in pages]
Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • 5
    Once read, obviously elegant (with the side effect to never use `map()` again...) – Ad N Mar 12 '13 at 22:56
  • 8
    @AdN: `map` has its uses. `map(f, lst)` is less repetitive than `[f(x) for x in lst]`. – Fred Foo Mar 13 '13 at 00:23
  • Why not a simple loop? Seriously? Why complicate things? for p in pages: myFunc(p, additionalArgument) – AFP_555 Mar 19 '18 at 02:13
  • 4
    @AFP_555 speed. A `for` loop is several orders of magnitude slower than mapping. This matters when you're working with millions of objects. – Joseph Farah Feb 09 '19 at 01:45
  • 2
    @JosephFarah No, the for loop isn't slower, and certainly not by several orders of magnitude. Why would it be? If you need a list of the results of the function calls, use the list comprehension. If you just want to call the functions, use a for loop. – Sven Marnach Mar 17 '20 at 09:41
  • @SvenMarnach will remove. I made the comment when I was less experienced and thought a single test was conclusive. Thanks for the correction. – Nick Brady Mar 18 '20 at 16:13
  • @AFP_555 While this is a very long time after the fact, map is very useful for tensors where you can't use for loops. – GameDungeon Dec 12 '21 at 18:42
52

You could use a list comprehension

[myFunc(p, additionalArgument) for p in pages]

or functools.partial()

map(functools.partial(myFunc, some_arg=additionalArgument), pages)
Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • This should be the accepted answer. A list comprehension is more simple while the `map()` function is more faster. The `functools.partial()` method should be used when there's speed requirement. And this version can be also useful to `multiprocessing.pool.map()`. – C.K. Mar 17 '20 at 00:16
  • 3
    @C.K.I don't expect `map(partial(...), ...)` to be faster than a list comprehension, except maybe in a few corner cases. I just added it for completeness and use cases like `pool.map()`. I think the accepted answer is perfectly fine, since the list comprehension is generally considered the most idiomatic solution for this use case. What's beyond me is how on earth the `map(lambda: ..., ...)` answer added years later got voted so highly – it's slower, less succinct and less readable than the list comprehension. – Sven Marnach Mar 17 '20 at 09:28
3

Note that if you're planning to use map for distributed computations (i.e. using multiprocessing) it will not unpack the arguments as one could expect. Say you want to distribute your call to myFunc (which accepts two arguments: page and additionalArgument) with:

pages = [p1, p2, p3, p4, p5...]

If you specify a list of args (tuples), i.e.

args = [(page, additionalArgument) for page in pages]

map will not unpack the args tuple and will pass only one argument (tuple) to myFunc:

pool.map(myFunc, args)  # map does not unpack the tuple

You will need to use multiprocessing.starmap instead

starmap is like map() except that the elements of the iterable are expected to be iterables that are unpacked as arguments.

i.e.

pool.starmap(myFunc, args)  # tuples are unpacked and two arguments are passed to myFunc
Tomasz Bartkowiak
  • 12,154
  • 4
  • 57
  • 62