9

In the sum function, the prototype is sum(iterable[,start]), which sums everything in the iterable object plus the start value. I wonder why there is a start value in here? Is there nay particular use case this value is needed?

Please don't give any more examples how start is used. I am wondering why it exist in this function. If the prototype of sum function is only sum(iterable), and return None if iterable is empty, everything will just work. So why we need start in here?

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
FrostNovaZzz
  • 802
  • 3
  • 10
  • 22

1 Answers1

16

If you are summing things that aren't integers you may need to provide a start value to avoid an error.

>>> from datetime import timedelta
>>> timedeltas = [timedelta(1), timedelta(2)]

>>> sum(timedeltas)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'datetime.timedelta'

>>> sum(timedeltas, timedelta())
datetime.timedelta(3)
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • 7
    And more generally `sum` is a kind of [foldr](http://en.wikipedia.org/wiki/Fold_%28higher-order_function%29) function which might require an initial value (*z* in the Wikipedia article). – Ben Jackson Dec 28 '10 at 01:56
  • 2
    That is because start is default to 0, and timedelta cannot add int. If originally there is no start param, no problem will exist in here. So why there is a start param after all? – FrostNovaZzz Dec 28 '10 at 03:22
  • 1
    Because otherwise, what do you add the first element to? – Karl Knechtel Dec 28 '10 at 05:58
  • 6
    @Karl Knechtel, @ziliangdotme: sum() can be implemented without adding the first element to anything. The real problem is that without a `start` argument, you face a dilemma deciding what to return if the iterable is empty. – John Machin Dec 28 '10 at 06:26
  • 4
    Another example that I personally love is when you have `[[1, 2 , 3], [4, 5, 6], [7, 8, 9]]` and you want `[1, 2, 3, 4, 5, 6, 7, 8, 9]`. You can do a simple `sum([[1, 2 , 3], [4, 5, 6], [7, 8, 9]], [])` to join all the lists on a list. – razpeitia Dec 28 '10 at 06:45
  • @razpeita you don't need a [] in here, the lists will sum up by themselves. – FrostNovaZzz Dec 28 '10 at 08:24
  • @ziliangdotme: Are you sure about that? It doesn't work for me without the `[]`. – Mark Byers Dec 28 '10 at 08:51
  • @Mark it doesn't work because start is default to 0. It there is no start param, everything will be just fine. – FrostNovaZzz Dec 28 '10 at 11:36
  • @ziliangdotme: If there isn't a start parameter, what would it start with? – Mark Byers Dec 28 '10 at 13:18
  • @Mark Can't it just sum within the iterable object? – FrostNovaZzz Dec 29 '10 at 05:44
  • @ziliangdotme: Not necessarily. Imagine if there were a character type (there isn't in Python, but just play along for the sake of example). `sum(['a', 'b'], '')` would give `'ab'` but treating the characters as integers, i.e. `sum(['a', 'b'], 0)` would give 195. If you don't have a start param, how would you be able to choose how to add? Also, what should the result of `sum([])` be? – Mark Byers Dec 29 '10 at 08:45
  • @Mark yes, that is a little convincing now :) – FrostNovaZzz Dec 29 '10 at 13:47
  • 3
    @JohnMachin's answer about the empty iterable is the only thing that makes sense. Using the first element as start value by default would have been nicer otherwise, I think. For example when adding `Counter`s together, you have to do this: `sum(counters, start=Counter())` when `sum(counters)` would have been so much nicer. – André Laszlo Jan 26 '15 at 16:18
  • @AndréLaszlo You're right, this answer didn't actually answer the question, and so far there isn't a good answer other than "it's always been like this". A pythonic way to handle an empty iterable would be to raise an error like Python does for an empty string in join. – rovyko Nov 21 '18 at 20:18
  • 1
    @AndréLaszlo There is precisely the function that you are asking for. E.g., `functools.reduce(operator.add, an_iterable)` would sum `an_iterable`, and raise `TypeError: reduce() of empty sequence with no initial value` if `an_iterable` is empty. Arguably, this is much cleaner; and maybe for consistency, `sum` should have done the same. However, the last time when this might have been worth discussing was probably 30 years ago, since by now changing `sum` to not use `0` as the default initial value would break a lot code. – max Dec 31 '19 at 03:29