Hi,
maybe you could do this by a decorator on the setattr method. It should look more or less
like your implementation, but in my eyes it's a cleaner and can be reused.

Further, I would use a stack for each attribute, so that you can restore all previous values.

bg,
Johannes

On 03/06/2013 05:07 PM, Ben Sizer wrote:
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,

--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to