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?
CodePudding user response:
A very rough idea how this can be done (with a lot of work left to you):
class dict_obs(dict):
def __init__(self, observer, *args, **kwargs):
self._observer = observer
super().__init__(*args, **kwargs)
def __setitem__(self, key, value):
self._observer.notify(key)
super().__setitem__(key, value)
class Indicator:
def notify(self, key):
print(f"{key} changed")
observer = Indicator()
d = dict_obs(observer, {1:1,2:2,3:3})
d[2] = 5
Prints
2 changed
CodePudding user response:
Your issue is with this line:
new.values = {k: self.elements.get(k, 0) other.elements.get(k, 0) for k in set(self.elements) | set(other.elements)}
You are creating sets of k:v pairs when you really only want the keys. Here is a working solution:
class Indicator:
def __init__(self, elements={}):
self.elements = elements
def __add__(self, other):
keys = set(self.elements.keys()).union(set(other.elements.keys()))
new = {}
for k in keys:
new[k] = self.elements.get(k,0) other.elements.get(k,0)
return Indicator(new)