How lambda works with decrement

I tried to understand how it reduce

works through this site. The example they mentioned is pretty good and easy to understand.

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

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

      

The above function will be a multiple of each quantity in the list and assign a

.

However, I stopped completely when I stumbled upon the following function in the project.

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

      

can someone help me to break down this function to understand what it should do

+3


source to share


3 answers


lambda

you can hardly give in to expressions, and even more so with this, because it returns a new function, also defined with lambda

.

Here's the same expression, but with some different line spacing:

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

      

Now I'll expand on this further by introducing lambda

, passed reduce

in as regular operators 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)

      

Recall what reduce

works by providing it with a method that takes 2 arguments, a sequence of objects (in this case a sequence of functions), and an optional initial value.

reduce(reduce_fn, objs, first_obj)

      

If no initial value is specified, the abbreviation will take the first object in the sequence, as if you named it like this:



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

      

Then the decrease function is called like this:

accumulator = first_obj
for obj in objs:
    accumulator = reduce_fn(accumulator, obj)
return accumulator

      

So, what your posted operator reduce

does is create a large function by combining several smaller ones.

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

      

So to:

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

      

+1


source


What reduce

is just a function composer. It takes an iteration of functions and combines them.

One important point reduce

is that when passing 2 arguments to your function (in this case acc

, fn

) depending on how you use them, python iterates first uses the last two arguments and in subsequent iterations it uses the result of the last calculation instead of the second argument passed to lamda

or any function passed as a constructor in reduce

(in this case fn

). Now, for a better demonstration, here are all the arguments passed to reduce

:

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

  • using the second function can pass arguments to the inner function on each iteration.

iterative argument: fns

initial argument: lambda _: _



If present, it is placed before the elements of the sequence in the calculation and is used by default when the sequence is empty.

As you can see in the passed function, it calls the inner functions with arguments and passes it to the next function, for example fog

in math, which is f(g(x))

. But since you can pass undefined number of arguments to reduce this function, you can write multiple functions.

Here's an example:

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

      

Also note that this is not a pythonic and recommended way of composing functions at all. Because, first of all, it is not readable and easy to understand, and secondly, it uses many additional function calls that are not optimal for such a task.

+2


source


Not very readable at first sight. Let it decompose:

First, it def compose(*fns):

means that the link function will receive an unknown number of arguments.

Next, we expand the decrease function:

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

      

As the doc shows , it reduce

takes 3 arguments:

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

      

So in your case: function

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

, fns

- this iterable

, and it will initialize withlambda _: _

initializer

indicates that the arguments compose

will be functions. lambda _: _

is a "neutral" for a function (just like "0" for addition or "1" for multiplication). I assume this exists when fns is empty.

Now for the main part:

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

      

it is a function that takes two functions acc

and fn

and returns a lambda function lambda *args: acc(fn(*args))

.

Let's take an example:

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

      

Here acc and fn are not functions, but integers. acc

is the "accumulated / reduced" so far, but fn

is the "next" step.

With functions it will be the same as acc

"callable functions" and fn the next function.

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

will return a function (lambda) that will return acc(fn(the_arguments))

.

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

will then return a function consisting of applying each function from fns

to its arguments, with a default identifier ( lambda _: _

).

Let's take an 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

      

So, g(x) = square(increment(half(x)))


With Kasramvd example :

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

      

matches:

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

      

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

will return [2,4]

and max([2,4])

equal to 4. Socompose(max, min)([[2, 4], [3, 5]])=4

+2


source







All Articles