I am trying to make an object that can track when its attributes have been assigned new values, and which can rollback to previous values where necessary. I have the following code which I believe works, but would like to know if there are simpler ways to achieve this goal, or if there are any bugs I haven't seen yet.
class ChangeTrackingObject(object): def __init__(self): self.clean() def clean(self): """Mark all attributes as unmodified.""" object.__setattr__(self, '_dirty_attributes', dict()) def dirty_vals(self): """Returns all dirty values.""" return dict( [ (k,v) for k,v in self.__dict__.iteritems() if k in self._dirty_attributes] ) def get_changes_and_clean(self): """Helper that collects all the changes and returns them, cleaning the dirty flags at the same time.""" changes = self.dirty_vals() self.clean() return changes def rollback(self): """Reset attributes to their previous values.""" for k,v in self._dirty_attributes.iteritems(): object.__setattr__(self, k, v) self.clean() def __setattr__(self, key, value): # If the first modification to this attribute, store the old value if key not in self._dirty_attributes: if key in self.__dict__: self._dirty_attributes[key] = object.__getattribute__(self, key) else: self._dirty_attributes[key] = None # Set the new value object.__setattr__(self, key, value) I am aware that adding a new attribute and then calling rollback() leaves the new attribute in place with a None value - maybe I can use a special DeleteMe marker object in the _dirty_attributes dict along with a loop that calls delattr on any attribute that has that value after a rollback. I also believe that this won't catch modification to existing attributes as opposed to assignments: eg. if one of the attributes is a list and I append to it, this system won't notice. Is that something I can rectify easily? Any other comments or suggestions? Thanks, -- Ben Sizer -- http://mail.python.org/mailman/listinfo/python-list