15

Given the following function f with two arguments, what is the standard way to apply map to only x?

def f (x,y):
    print x,y

More specifically, I would like to perform the following operation with map in one line.

list=[1,2,3]
fixed=10
for s in list:
    f(s,fixed)

One way to do so is:

import functools
map(functools.partial(lambda x,y:f(y,x),fixed),list)

What is a better way?

Alfad
  • 181
  • 1
  • 2
  • 4

4 Answers4

26

First of all, there is no need to use lambda AND partial - they are alternatives:

map(lambda x:f(x,fixed),srclist)

Secondly, you could just bind the second argument with partial, as long as you know the argument's name:

map(functools.partial(f,y=fixed),srclist)

Alternatively, use a list comprehension:

[f(x, fixed) for x in srclist]
Marcin
  • 48,559
  • 18
  • 128
  • 201
  • 1
    Can you comment on how the performance of these three methods stack up? – chase Feb 11 '14 at 20:24
  • 1
    @chase Well, the last one involves no actual partial application, so it avoids any overhead. As to the other two, I can't say. This sort of micro-optimisation shouldn't happen until you identify a hotspot anyway. – Marcin Feb 11 '14 at 22:08
  • Generally I agree. Although occasionally one goes searching through 2-year old SO questions when they've found a hotspot ;) Should be easy enough to profile, although I personally prefer the last solution for clarity. – chase Feb 11 '14 at 23:01
  • @chase Then do that, for sure. – Marcin Feb 11 '14 at 23:05
6

Given the following function f with two arguments, what is the standard way to apply map to only x?

A little discussion on currying and partial application

In FP terms, your function f is "uncurried" - while it conceptually takes two arguments, they're bundled in a single product structure. In Python, everything is uncurried, all the time. You have to give all the arguments at once, or none of them.

To work around this, there are various tricks, but conceptually you just want to "curry" the function. That is, transform f(x,y) into f(x) which returns a new function g(y).

In languages which are curried by default , you can write this translation easily as:

-- curry: take a function from (x,y) to one from x to a function from y to z
curry :: ((x,y) -> z) -> (x -> y -> z)
curry f x y     = f (x, y)

So curry takes your curried f and its product arguments, separately, and applies the arguments once they are all available. The opposite is also pretty easy:

uncurry :: (x -> y -> z) -> ((x,y) -> z)
uncurry f (x,y) =  f x y

How does this relate to partial application?

  • Currying takes a function that takes a structure of 1 (n-product) argument, and returns a new function taking n arguments.
  • Partial application takes a function of n arguments and applies them to k arguments, yielding a function of n-k remaining arguments.

In an uncurried language, each of the arguments can be applied in turn (e.g. partially, with respect to the arity of the function). In a curried language, you have to play some tricks to uncurry the function first, as in the above examples.

I think it is more flexible to be in a curried-by-default environment, as partial application is free. In such an environment, it is common to chain together functions that modify a data structure into a pipeline. E.g. a pipeline of integer modifications:

(+1) . (*2) . (^3) $ 7

is just a chain of partially applied, uncurried functions, composed, each operating on the output of the previous function. This can be nice, as it separates concerns visually.

Community
  • 1
  • 1
Don Stewart
  • 137,316
  • 36
  • 365
  • 468
5
map(lambda x: f(fixed,x), thelist)

Or don't even use map() at all, use list comprehensions instead.

[f(fixed, x) for x in thelist]

PS: don't use list as a variable name, it's an important built-in name (the list type).

ddaa
  • 52,890
  • 7
  • 50
  • 59
2

What's wrong with:

def add(x, y):
    return x + y

l = [1, 2, 3]

from functools import partial
plus10 = map(partial(add, y=10), l)
print plus10

## [11, 12, 13]
georg
  • 211,518
  • 52
  • 313
  • 390
  • It's unreadable (and I thought python was self-explaining?). The list comprehension examples are much more readable. – Ingo May 05 '12 at 23:58
  • @Ingo: sure, except the OP didn't say anything about comprehensions. – georg May 06 '12 at 10:35