2017-08-04 7 views
3

私はこのウェブサイトを通じてreduceの仕組みを理解しようとしていました。彼らが言及した例は非常によく理解しやすいです。リスト内ラムダと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 _: _) 

誰かが故障、この機能を、reduceは単なる関数作曲されていることを

答えて

1

lambda式4です。ここで

は、同じ表現であるが、いくつかの異なる線間隔で:

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) 

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

は今、私はさらに、通常のdef文としてreduceに渡さlambda Sを爆発することによって、これを拡張します

reduceは、2つの引数、一連のオブジェクト(この場合は一連の関数)、およびオプションの初期値を取るメソッドを与えることによって機能します。

reduce(reduce_fn, objs, first_obj) 

何の初期値が与えられない場合、あなたがそれを呼ばれたかのように、好き、シーケンス内の最初のオブジェクトを取る減らす:

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

だからそれを:

resulting_function(2) -> (((2 + 3) * 5) + 1) -> 26 
+0

これは本当に混乱する関数です。本当にシンプルにしてくれてありがとう。 –

2

を行うこととしているものを理解するために私を助けることができます。それは、反復可能な関数を受け入れ、それらを結合する。

reduceについての一つの重要なポイントは、あなたが最初の反復のpythonで、それらを使用しているどのように基づいて(この場合accfnに)あなたの関数に2つの引数を渡すときのではなく、あなたのiterableの最後の2つの引数を使用していることですその次の反復では、lamdaに渡された2番目の引数またはreduce(この場合はfn)にコンストラクタとして渡された関数の代わりに最新の計算結果を使用します。今より良いデモはこちらを区別してreduceに渡されるすべての引数は次のとおりです。

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

  • 第二の機能を使用すると、各反復で、内側の関数に引数を渡すことができることです。

反復可能な引数:fns

初期引数:初期が存在する場合lambda _: _

、それは計算における配列のアイテム 前に置かれ、デフォルトとして機能する場合 シーケンスは空です。

あなたが渡された関数で見ることができるように、それは引数を持つ内部関数を呼び出し、f(g(x))ある数学のfogのような次の関数に渡します。しかし、この関数を減らすために引数の数を渡すことができますので、複数の関数を構成することができます。ここで

は一例です:

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

はまた、これはニシキヘビのではないことに注意して、すべての機能を構成する方法をお勧めします。まず第一に、それは読みにくくてわかりやすく、第二に、そのようなタスクには最適ではないたくさんの余分な関数呼び出しを使用しているからです。

2

一見するとあまり読みにくくありません。

まず、def compose(*fns):は、作成関数が未知数の引数を受け取ることを意味します。

次は、機能を減らす分解してみましょう:

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))あり、fnsがありますiterableと初期化されます。lambda _: _

initializerは、composeの引数が関数になることを示します。 lambda _: _は、関数の中立要素です(加算の場合は「0」、乗算の場合は「1」と同じです)。私はそれが本質的にfnsが空の時だと思う。メイン部分のための今

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

これは2つの機能accfnを取る関数であり、ラムダ関数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))は(λ)関数を返します。この関数はacc(fn(the_arguments))を返します。

reduce(lambda acc, fn: lambda *args: acc(fn(*args)), fns, lambda _: _)は、fnsの各関数をそのargsに適用して、デフォルトでID(lambda _: _)を持つ関数を返します。 Kasramvd's example

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

は同じであり、 0

min([[2, 4], [3, 5]])意志[2,4]を返し、max([2,4])lambdaを使用して定義され、従うことが困難であり、特に新たな機能を返しこのいずれかとなることができるこのようcompose(max, min)([[2, 4], [3, 5]])=4

+0

私が好き_ "' initializer'はcompose' 'の引数が関数になることを示している'ラムダ_:。_'ある機能について»ニュートラル要素« (加算の場合は「0」、乗算の場合は「1」と同じです)。 "_ – gboffi