class Value: def __init__(self, initial=None): self.value = initial self.has_changed = True def set(self, value): self.has_changed = self.value != value self.value = value def is_changed(self): return self.has_changed def get(self): self.has_changed = False return self.value class ValueChanged(object): def __init__(self, on_changed, prec=2, initial=None): self.on_changed = on_changed self.prec = prec self.value = initial def set(self, value): has_changed = True value_rounded = round(value, self.prec) if self.value is not None: has_changed = self.value != value_rounded self.value = value_rounded if has_changed: self.on_changed(value_rounded) class AttributeChange(object): callbacks = {} def set_on_changed(self, key, on_changed: ValueChanged): if key not in self.callbacks: self.callbacks[key] = on_changed def __setattr__(self, key, value): try: old = super().__getattribute__(key) print("Change: {} from {} to {}".format(key, old, value)) except: print("Create: {} and initialize with {}".format(key, value)) super().__setattr__(key, value) if key in self.callbacks: self.callbacks[key].set(value)