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 ChangedFloat(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 ChangedInteger(object): def __init__(self, on_changed, initial=None): self.on_changed = on_changed self.value = initial def set(self, value): value = round(value) has_changed = True if self.value is not None: has_changed = self.value != value self.value = value if has_changed: self.on_changed(value) class AttributeChange(object): def __init__(self): self.callbacks = {} def set_on_changed(self, key, on_changed): if key not in self.callbacks: self.callbacks[key] = [on_changed] else: self.callbacks[key].append(on_changed) def __setattr__(self, key, value): try: old = super().__getattribute__(key) except: pass super().__setattr__(key, value) if key in self.callbacks: for cb in self.callbacks[key]: cb(value)