lambda如何使用reduce

时间:2017-08-04 09:43:05

标签: python python-2.7 lambda

我试图通过本网站了解reduce的工作原理。他们提到的例子非常好且易于理解。

http://book.pythontips.com/en/latest/map_filter.html#reduce

a = reduce((lambda x, y: x * y), [1, 2, 3, 4])

上述功能会将列表中的每个数字复用并分配给a

然而,当我在项目中遇到以下功能时,我完全陷入困境。

def compose(*fns):
    return reduce(lambda acc, fn: lambda *args: acc(fn(*args)), fns, lambda _: _)

有人可以帮我分解这个功能,以了解它的假设吗

3 个答案:

答案 0 :(得分:2)

reduce只是一个功能作曲家。它接受一个可迭代的函数并将它们组合在一起。

关于reduce的一个要点是,当您根据您使用它们的方式将2个参数传递给函数时(在本例中为accfn),在第一次迭代时python使用迭代中的最后两个参数而不是它们,并且在下一次迭代中,它使用最新计算的结果而不是传递给lamda的第二个参数或作为构造函数传递给reduce的任何函数。 (在这种情况下fn)。现在,为了更好地演示,所有传递给reduce的参数都是区别的:

功能:lambda acc, fn: lambda *args: acc(fn(*args))

  • 使用第二个函数能够在每次迭代时将参数传递给内部函数。

可迭代参数:fns

初始论证:lambda _: _

  

如果存在初始值,则将其放在项目之前   计算中的序列,并作为默认值   序列是空的。

正如您在传递函数中看到的那样,它使用参数调用内部函数,并将其传递给下一个函数,如数学中的fog f(g(x))。但是因为你可以传递一个未定义数量的参数来减少这个函数,所以可以组成多个函数。

以下是一个例子:

In [10]: compose(max, min)([[2, 4], [3, 5]])
Out[10]: 4

另请注意,这不是一种pythonic和推荐的组合功能的方法。因为首先它不可读并且易于理解,其次它使用了许多额外的函数调用,这对于这样的任务不是最佳的。

答案 1 :(得分:2)

乍一看不太可读。让我们分解:

首先,def compose(*fns):表示撰写函数将接收未知数量的参数。

接下来,让我们分解reduce函数:

reduce(
   lambda acc, fn: lambda *args: acc(fn(*args)),
   fns,
   lambda _: _
)

正如doc所示,reduce有3个参数:

def reduce(function, iterable, initializer=None):

因此,在您的情况下:functionlambda acc, fn: lambda *args: acc(fn(*args))fnsiterable,并且会使用lambda _: _进行初始化

initializer表示compose的参数将是函数。 lambda _: _是函数的“中性元素”(与“0”相加或“1”相乘)。我猜它基本上是在fns为空的时候。

现在主要部分:

lambda acc, fn: lambda *args: acc(fn(*args))

这是一个函数,它接受两个函数accfn并返回lambda函数lambda *args: acc(fn(*args))

我们举一个例子:

>>> reduce((lambda acc, fn: acc ** fn), [1, 2, 3, 4])
1
>>> reduce((lambda acc, fn: fn ** acc ), [1, 2, 3, 4])
262144

这里acc和fn不是函数,而是整数。到目前为止acc是“累积/减少”,fn是“下一步”。

对于函数,到目前为止acc将是“被调用的函数”,并且fn是下一个函数。

因此lambda acc, fn: lambda *args: acc(fn(*args))将返回一个(lambda)函数,该函数将返回acc(fn(the_arguments))

reduce(lambda acc, fn: lambda *args: acc(fn(*args)), fns, lambda _: _)将返回一个函数,该函数包含将fns的每个函数应用于其args,默认情况下为lambda _: _}。

我们举一个例子:

>>> def square(x):
...  return x**2
...
>>> def increment(x):
...   return x+1
...
>>> def half(x):
...   return x/2
...
>>> compose(square, increment, half)
<function <lambda> at 0x7f5321e13de8>
>>> g=compose(square, increment, half)
>>> g(5)
9

所以,g(x) = square(increment(half(x)))

使用Kasramvd's example

compose(max, min)([[2, 4], [3, 5]])

与:

相同
max(min([[2, 4], [3, 5]]))

min([[2, 4], [3, 5]])将返回[2,4]max([2,4])为4.因此compose(max, min)([[2, 4], [3, 5]])=4

答案 2 :(得分:1)

lambda表达式可能很难遵循,尤其是这个表达式,它返回一个新函数,也使用lambda定义。

这是相同的表达式,但有一些不同的行间距:

def compose(*fns):
    return reduce(lambda acc, fn: lambda *args: acc(fn(*args)), 
                  fns,
                  lambda _: _)

现在,我将通过将传递给lambda的{​​{1}}作为常规reduce语句展开来进一步扩展这一点:

def

回想一下def compose_2_fns(f, g): # take 2 functions and return a new function that calls the first with the # result of calling the second def composed(*args): return f(g(*args)) return composed def _initial(x): return x def compose(*fns): return reduce(compose_2_fns, fns, _initial) 的工作方式是给它一个带有2个参数的方法,一个对象序列(在本例中是一系列函数)和一个可选的初始值。

reduce

如果没有给出初始值,则reduce将获取序列中的第一个对象,就像你调用它一样:

reduce(reduce_fn, objs, first_obj)

然后像这样调用reduce函数:

reduce(reduce_fn, objs[1:], objs[0])

所以你发布的accumulator = first_obj for obj in objs: accumulator = reduce_fn(accumulator, obj) return accumulator 语句正在做的是通过组合几个较小的函数来建立一个很大的功能。

reduce

那样:

functions = (add_1, mult_5, add_3)
resulting_function -> lambda *args: add_1(mult_5(add_3(*args)))