TheRealFakeNews
TheRealFakeNews

Reputation: 8153

Can Python's functool's reduce work with functions in the iterable?

I'm trying to figure out how to return a function in Python. However, I don't know if the issue is with reduce or with my code. What I currently have is this:

Code:

def combine(*args):
    from functools import reduce
    def closure(val):
        return reduce( (lambda x, f: f(x)), args, val)
    return closure


def first(array):
    return array[0]
def shift(array):
    return array[1:]
fifth = combine(first, shift, shift, shift, shift)
print(fifth([1,2,3,4,5,6,7,8,9]) # should return 5

However, I get the error message:

TypeError: 'int' object is not subscriptable

What's causing this?

Upvotes: 0

Views: 250

Answers (1)

Freyja
Freyja

Reputation: 40804

As it is defined in your question, fifth(x) is the same as:

fifth(x) = shift(shift(shift(shift(first(x)))))

Now, if x = [1,2,3,4,5,6,7,8,9], then

first(x) = 1

But that means that

shift(first(x)) = first(x)[1:] = 1[1:]

But as the error message tells us, 1 is not subscriptable.


I assume what's really causing this is a misconception about the order reduce works. It works from left to right, so the leftmost function given is applied first (i.e., innermost):

combine(a, b, c)(x) = c(b(a(x)))

If you instead wanted a(b(c(x))), you would have to either pass them to combine in the reverse order, or modify your defintion of combine so that it reverses the order of the arguments for you:

def combine(*args):
  from functools import reduce
  def closure(val):
    return reduce( (lambda x, f: f(x)), reversed(args), val)
  return closure

Upvotes: 2

Related Questions