我试图通过本网站了解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 _: _)
有人可以帮我分解这个功能,以了解它的假设吗
答案 0 :(得分:2)
reduce
只是一个功能作曲家。它接受一个可迭代的函数并将它们组合在一起。
关于reduce
的一个要点是,当您根据您使用它们的方式将2个参数传递给函数时(在本例中为acc
,fn
),在第一次迭代时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):
因此,在您的情况下:function
为lambda acc, fn: lambda *args: acc(fn(*args))
,fns
为iterable
,并且会使用lambda _: _
进行初始化
initializer
表示compose
的参数将是函数。 lambda _: _
是函数的“中性元素”(与“0”相加或“1”相乘)。我猜它基本上是在fns为空的时候。
现在主要部分:
lambda acc, fn: lambda *args: acc(fn(*args))
这是一个函数,它接受两个函数acc
和fn
并返回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)))
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)))