5

As I understand it, for it to be possible to cast sum() on an object, it must be an iterable, and must be "addable", i.e. it must implement methods __iter__ and __add__. However, when I do this for my class Point (just an example), this doesn't work.

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)

    def __iter__(self):
        return self

    def __str__(self):
        return str((self.x, self.y))


print(Point(2, 2) + Point(1, 1))
>>> (3, 3)    # As expected; good!

points = [Point(0, 0), Point(2, 0), Point(0, 2), Point(2, 2)]
print(sum(points))    # Expect (4, 4)
>>> TypeError: unsupported operand type(s) for +: 'int' and 'Point'

If I implement __radd__ the same as __add__ I then get an attribute error when I try sum():

AttributeError: 'int' object has no attribute 'x'

Based on the errors my Points are somewhere being separated to just ints but I'm not sure where. Thanks for any help.

4
  • Note that sum is not required to work for non-numeric types. It's not entirely clear, though, what sum will consider a numeric type. (For example, it works for lists, but explicitly rejects strs.) Commented Nov 18, 2019 at 14:15
  • Isn't that just because ''.join() is a better alternative for string concatenation than sum()? Edit, see this answer Commented Nov 18, 2019 at 14:18
  • It absolutely is, though I'm not entirely sure why sum can't be implemented to call join itself, rather than raise an exception. Commented Nov 18, 2019 at 14:24
  • I'm inclined to agree, a few others on the above thread agree too. Commented Nov 18, 2019 at 14:27

1 Answer 1

13

This happens because sum starts with a default value of int and when doing sum(points) what really is happening is sum is first trying to add 0 + Point(0, 0) and hence the error. If you check the help on sum, this will become pretty evident,

Help on built-in function sum in module builtins:

sum(iterable, start=0, /) Return the sum of a 'start' value (default: 0) plus an iterable of numbers

When the iterable is empty, return the start value.
This function is intended specifically for use with numeric values and may
reject non-numeric types.

Change the line from,

>>> print(sum(points))

to

>>> print(sum(points, Point(0, 0)))
Sign up to request clarification or add additional context in comments.

4 Comments

Interesting, thanks. I wonder why sum(sequence) was chosen to start from 0 rather than just add the elements left to right (or right to left). Maybe to handle cases where len(sequence) <= 1.
I am not too sure why the implementation chose that. I'd have to check : )
0 is just the default starting value, both to handle empty sequences and the normal use of simply summing the values. You can pass a different starting value if you like. sum(values, x) == x + sum(values). For example, sum([[1], [2]], [3]) == [3] + sum([[1], [2]], []) == [3, 1, 2].
Yeah, make sense to have the starting value as 0. It's easier to have a starting value, and since usually the iterable’s items are normally numbers, and the start value is not allowed to be a string.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.