83

There seems to be a lot of heated discussion on the net about the changes to the reduce() function in python 3.0 and how it should be removed. I am having a little difficulty understanding why this is the case; I find it quite reasonable to use it in a variety of cases. If the contempt was simply subjective, I cannot imagine that such a large number of people would care about it.

What am I missing? What is the problem with reduce()?

5 Answers 5

86

As Guido says in his The fate of reduce() in Python 3000 post:

So now reduce(). This is actually the one I've always hated most, because, apart from a few examples involving + or *, almost every time I see a reduce() call with a non-trivial function argument, I need to grab pen and paper to diagram what's actually being fed into that function before I understand what the reduce() is supposed to do. So in my mind, the applicability of reduce() is pretty much limited to associative operators, and in all other cases it's better to write out the accumulation loop explicitly.

There is an excellent example of a confusing reduce in the Functional Programming HOWTO article:

Quick, what's the following code doing?

total = reduce(lambda a, b: (0, a[1] + b[1]), items)[1]

You can figure it out, but it takes time to disentangle the expression to figure out what's going on. Using a short nested def statements makes things a little bit better:

def combine (a, b):
    return 0, a[1] + b[1]

total = reduce(combine, items)[1]

But it would be best of all if I had simply used a for loop:

total = 0
for a, b in items:
    total += b

Or the sum() built-in and a generator expression:

total = sum(b for a,b in items)

Many uses of reduce() are clearer when written as for loops.

Sign up to request clarification or add additional context in comments.

14 Comments

In that case it could be even easier: sum (b for a, b in items)
The reduce code is not equivalent to the for loop. Here is the equivalent: total = reduce(lambda total, (a,b): total + b, items, 0)
"The reduce function can obfuscate code's intent. Therefore, reduce should be removed from the language." Granted, I don't know that anyone is saying exactly that, but it is a non sequitur.
Point taken, but to be fair, tossing in a lambda into your example is the equivalent to handing a blood-stained shirt to one guy in the police lineup. I won't argue that reduce() isn't confusing at first, but everything in functools is when you start. I'm finding functools more and more useful as I learn to use them. Now, if you want examples of confusing, check out itertools(). I'm learning to love them too, but was a rough first date. :-)
The argument is "Let's move reduce because it can be used to write unclear code.". Well, so can **, + and -. Should we move them to functools ?
|
39

reduce() is not being removed -- it's simply being moved into the functools module. Guido's reasoning is that except for trivial cases like summation, code written using reduce() is usually clearer when written as an accumulation loop.

3 Comments

Gah, that's horrible reasoning :(
Is it? Much of Python's philosophy is about writing code that is clear and obvious. A typical call to reduce() usually requires me to break out a pencil and graph what the function is being called with.
Unless you can show me a significant performance increase (2x at least), I'll take "clear and obvious" over "compactness of expression" any day.
9

People worry it encourages an obfuscated style of programming, doing something that can be achieved with clearer methods.

I'm not against reduce myself, I also find it a useful tool sometimes.

Comments

4

The primary reason of reduce's existence is to avoid writing explicit for loops with accumulators. Even though python has some facilities to support the functional style, it is not encouraged. If you like the 'real' and not 'pythonic' functional style - use a modern Lisp (Clojure?) or Haskell instead.

3 Comments

This is like telling Chinese Americans to go back to China if they don't like how they are being treated here in the US. We are all here to make a widely used language better. No need to ask people to go use a different language. Most of the time they can't because constraints such as the availability of packages.
@episodeyang that's a strange metaphor with a lot of emotional baggage to bring into a technical discussion. Python isn't made "better" (or worse) by functional paradigms, it's simply not a functional language by the statement of its own creator. There's nothing wrong with calling a spade a spade and advising folks to stop shoehorning Lisp/Clojure/Haskell idioms into a multi-paradigm, fundamentally imperative, non-functional language like Python.
So to me, reduce is a special case of a loop. It's a loop where the input is List[T] and the output is T. I feel the example above is unnatural because the result of the loop is different, but they use a trick to embed it in T (they use (0, acc) for the accumulator). My use case at the moment is to calculate a ++ b ++ c ++ d ++ e without either having to i. create a "zero" in T or b mess around with "loop and a half logic" (acc = loop[0]; for x in loop[1:]: acc = acc ++ x)
-1

Using reduce to compute the value of a polynomial with Horner's method is both compact and expressive.

Compute polynomial value at x. a is an array of coefficients for the polynomial

def poynomialValue(a,x):
   return reduce(lambda value, coef: value*x + coef, a)

3 Comments

This isn't really attempting to answer the OP's question. "Why is reduce a problem?" Answer: "Here's a use case for reduce".
A powerful language tool can always be used to give brevity but lack clarity. I wanted to give an example where reduce could be used to compactly express an algorithm. Note that this is an example of an operator that is not associative.
Nobody is arguing reduce can never be used clearly or even that there aren't plenty of examples where it's a great fit. The question is what's wrong with it, not what's right with it. The arguments against reduce are that it tends to be misapplied, harms readability and doesn't fit in with the non-functional orientation of Python. These are the sort of possible answers to OP's question as to why it was relegated to functools.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.