4

If I have a value, and a list of additional terms I want multiplied to the value:

n = 10
terms = [1,2,3,4]

Is it possible to use a list comprehension to do something like this:

n *= (term for term in terms) #not working...

Or is the only way:

n *= reduce(lambda x,y: x*y, terms)

This is on Python 2.6.2. Thanks!

Sasha Chedygov
  • 127,549
  • 26
  • 102
  • 115
bigjim
  • 938
  • 1
  • 9
  • 18
  • 1
    See also [Which Python module is suitable for data manipulation in a list?](http://stackoverflow.com/questions/595374/whats-the-python-function-like-sum-but-for-multiplication) – outis Oct 01 '10 at 22:10

3 Answers3

8

reduce is the best way to do this IMO, but you don't have to use a lambda; instead, you can use the * operator directly:

import operator
n *= reduce(operator.mul, terms)

n is now 240. See the docs for the operator module for more info.

Sasha Chedygov
  • 127,549
  • 26
  • 102
  • 115
7

Reduce is not the only way. You can also write it as a simple loop:

for term in terms:
    n *= term

I think this is much more clear than using reduce, especially when you consider that many Python programmers have never seen reduce and the name does little to convey to people who see it for the first time what it actually does.

Pythonic does not mean write everything as comprehensions or always use a functional style if possible. Python is a multi-paradigm language and writing simple imperative code when appropriate is Pythonic.

Guido van Rossum also doesn't want reduce in Python:

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 aren't a whole lot of associative operators. (Those are operators X for which (a X b) X c equals a X (b X c).) I think it's just about limited to +, *, &, |, ^, and shortcut and/or. We already have sum(); I'd happily trade reduce() for product(), so that takes care of the two most common uses. [...]

In Python 3 reduce has been moved to the functools module.

Community
  • 1
  • 1
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • My thoughts exactly, just a minute quicker! – JoshD Oct 01 '10 at 21:39
  • 1
    I thought "pythonic" meant "write everything in one line" – Falmarri Oct 01 '10 at 22:08
  • 3
    Hmm, he's added `any()` and `all()` (which he proposed in the next paragraph after that quote), but never has added `product()`. Regardless of the ultimate fate of `reduce` (and I've never had any trouble reading it), `n *= product(terms)` is pretty clear. I think that deciding between a loop or a reduce call or whatever is less important than putting it in a well-named function. – Ken Oct 01 '10 at 22:09
  • 1
    Falmarri: No, you're thinking of APLic! – Ken Oct 01 '10 at 22:10
  • I'd argue against that. If you expect that people can't read your Code, than there is no good way of writing it. I admit that the python community is not very fond of functional programming, but reduce is as clear and easy as it gets. Not in anyway inferior to a for loop in terms of readability. – Nima Mousavi Apr 04 '19 at 12:38
2

Yet another way:

import operator
n = reduce(operator.mul, terms, n)
Bolo
  • 11,542
  • 7
  • 41
  • 60