ldocao
ldocao

Reputation: 139

Sum a list of object attributes

I have a class defined as

class MyClass(object):

    def __init__(self, value=0):
        self.value = value

    def __add__(self,other):
        return MyClass(self.value + other.value)

    __radd__ = __add__

I would like simply to apply the sum function to them like this:

a=MyClass(value=1)
b=MyClass(value=2)

c=[a,b]
print sum(c)  # should return a MyClass instance with value 3

as was suggested in this post. However, an exception is raised:

     15 
     16 c=[a,b]
---> 17 print sum(c)

TypeError: unsupported operand type(s) for +: 'int' and 'MyClass'

I don't understand why the sum function wants to add two different types.

Upvotes: 2

Views: 3353

Answers (2)

jonrsharpe
jonrsharpe

Reputation: 121975

sum needs somewhere to start; by default, it starts at 0. So the first operation it attempts is 0 + MyClass(value=1), which you haven't told it how to do!

You therefore have two choices, either:

  1. Specify the start (e.g. sum(c, MyClass())); or
  2. Tell MyClass how to deal with adding integers to instances.

The latter could look like:

class MyClass(object):

    ...

    def __add__(self, other):
        try:
            return MyClass(self.value + other.value)  # handle things with value attributes
        except AttributeError:
            return MyClass(self.value + other)  # but also things without

    ...

which lets you skip the explicit start:

>>> sum([MyClass(1), MyClass(2)]).value
3

Upvotes: 4

yangjie
yangjie

Reputation: 6715

Because sum(iterable[, start]) sums start and the items of an iterable from left to right and returns the total. start defaults to 0.

You can modify the class by

class MyClass(object):

    def __init__(self, value=0):
        self.value = value

    def __add__(self, other):
        if (isinstance(other, MyClass)):
            return MyClass(other.value + self.value)
        else:
            return MyClass(other + self.value)

    __radd__ = __add__

Upvotes: 2

Related Questions