I want to create a class in Python that implements a __add__ object method that allows summing two objects of the same class. Let's call this class Indicator and the two objects to sum ind1 and ind2. The Indicator object has only one property elements , which is a dictionary of integer values.
My implementation of __add__ combines the elements properties of two objects, eventually summing those values with the same key.
from __future__ import annotations
import copy
class Indicator:
def __init__(self, elements={}):
self.elements = elements
def __add__(self, other: Indicator):
new = copy.deepcopy(self)
new.values = {k: self.elements.get(k, 0) + other.elements.get(k, 0) for k in set(self.elements) | set(other.elements)}
return new
ind1 = Indicator({1:1,2:2,3:3})
ind2 = Indicator({1:1,2:2})
new = ind1 + ind2
print('ind1: ',ind1.elements)
print('ind2: ',ind2.elements)
print(new.elements) # {1: 2, 2: 4, 3: 3}
I would like __add__ to return an object whose elements property gets updated as one or both objects in the summation get updated along the code flow.
For example,
ind1.elements[4] = 4
print(new.elements) # I would like this to be {1: 2, 2: 4, 3: 3, 4:4}
ind1.elements[1] = 3
print(new.elements) # I would like this to be {1: 4, 2: 4, 3: 3, 4:4}
How can I do it?
EDIT
First of all, let me thank you all the users who posted a comment/answer. Following the suggestions given in the comments and answers, I came up with the following solution. The idea is to add two lists as properties of Indicator: self.adds and self.linked.
The list
self.addscollects the addends of the summation. It gets filled up when__add__is called. So, in the example below,ind1.adds is []andind2.adds is []since both objects don't arise from a sum. On the contrary,new.adds is [ind1,ind2]The list
self.linkedcollects all those object that needs to be updated wheneverselfgets updated. In the example below,ind1.linked is [new]andind2.linked is [new].
I am not completely satisfied with this solution. For example, it fails to work if we sum up three objects and then modify one of them. I can try to fix the code, but I am wondering if I am doing something unconventional. Any thoughts? The code is the following
from __future__ import annotations
import copy
class Indicator:
def __init__(self, elements=None):
if elements is None:
self._elements = {}
else:
self._elements = elements
self.adds = []
self.linked = []
@property
def elements(self):
return self._elements
@elements.setter
def elements(self, value):
self._elements = value
for i in range(len(self.linked)):
el = self.linked[i]
el.update()
def update(self):
summation = self.adds[0]
for obj in self.adds[1:]:
summation = summation.__add__(obj)
self._elements = summation.elements
def __add__(self, other: Indicator):
new = copy.deepcopy(self)
self.linked.append(new)
other.linked.append(new)
new.adds = [self, other]
new._elements = {k: self.elements.get(k, 0) + other.elements.get(k, 0) for k in
set(self.elements) | set(other.elements)}
return new
ind1 = Indicator({1: 1, 2: 2, 3: 3})
ind2 = Indicator({1: 1, 2: 2})
new = ind1 + ind2
print('ind1: ', ind1.elements)
print('ind2: ', ind2.elements)
print(new.elements) # {1: 2, 2: 4, 3: 3}
ind1.elements = {0: 0, 1: 3}
print('Updating ind1: ',new.elements == (ind1+ind2).elements)
ind2.elements = {0: 0, 7: 9}
print('Updating ind2: ',new.elements == (ind1+ind2).elements)