应用map函数的部分参数

15

给定具有两个参数的函数f,如何标准地只将map应用于x?

def f (x,y):
    print x,y
更具体地说,我想在一行中使用map执行以下操作。
list=[1,2,3]
fixed=10
for s in list:
    f(s,fixed)

实现这个目标的一种方法是:

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

有更好的方法吗?

4个回答

26

首先,没有必要同时使用lambda和partial——它们是可替代的:

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

其次,只要你知道参数的名称,你可以使用 partial 绑定第二个参数:

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

或者,使用列表推导式:

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

1
你能否对这三种方法的性能进行评论? - chase
1
@chase 好的,最后一个不涉及任何实际的部分应用,因此避免了任何开销。至于另外两个,我无法确定。这种微观优化在你识别出热点之前不应该发生。 - Marcin
一般我同意。尽管有时候当我们找到一个热点时会去查找两年前的SO问题 ;) 应该很容易进行性能分析,不过出于清晰起见,我个人更喜欢最后一个解决方案。 - chase
@chase 那肯定要这样做。 - Marcin

6

给定以下具有两个参数的函数f,如何标准地将map应用于仅x?

关于柯里化和部分应用的讨论

从FP角度来看,您的函数f"未柯里化"的 - 虽然它在概念上接受两个参数,但它们被捆绑在一个单一的产品结构中。在Python中,所有东西都是未柯里化的。您必须一次性提供所有参数或不提供任何参数。

为了解决这个问题,有各种技巧,但在概念上,您只想“柯里化”该函数。也就是说,将f(x,y)转换为返回新函数g(y)f(x)

在默认为柯里化的语言中,您可以轻松编写此翻译:

-- 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)

所以 curry 接受你的咖喱化的 f 和它的参数,分别地,并在所有参数都可用时应用这些参数。相反的操作也很容易:
uncurry :: (x -> y -> z) -> ((x,y) -> z)
uncurry f (x,y) =  f x y

这与部分应用有什么关系?

  • 柯里化将接受一个结构为1n-乘积)参数的函数,并返回一个接受n个参数的新函数。
  • 部分应用将一个n参数的函数应用于k个参数,产生一个剩余n-k个参数的函数。

在非柯里化语言中,每个参数都可以依次应用(例如,部分地,关于函数的arity)。在柯里化语言中,您必须首先玩一些技巧来取消柯里化函数,就像上面的例子一样。

我认为在默认情况下处于柯里化环境中更加灵活,因为部分应用是免费的。在这样的环境中,常见的是将修改数据结构为管道的函数链接在一起。例如,整数修改的管道:

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

它只是一系列部分应用的、非科里化函数,每个函数都组合起来,作用于前一个函数的输出。这很好,因为它在视觉上分离了关注点。


5
map(lambda x: f(fixed,x), thelist)

或者干脆不使用 map(),改用列表推导式。

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

PS:不要使用list作为变量名,这是一个重要的内置名称(列表类型)。


2

以下是有关以下代码的解释:

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]

这是不可读的(我还以为Python是自解释的?)。列表推导式的例子更易读。 - Ingo
@Ingo:好的,除了原帖没有提到任何关于推导式的内容。 - georg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接