12
votes

Anyone know of any easy way to track changes to a dictionary object in python? I am at a high level doing crud, so I have a couple methods that handle changing a dictionary, if the dictionary changes I want to call a function to basically do an Observer/Notify.

 class MyClass(object):
     def update(self, item):
        changed = False

        if(self.my_dict.has_key(item.id)):
           self.my_dict[item.id] = item
           changed = True

        if(changed):
          self.notify()

What I am trying to avoid is all of the tracking(setting the boolean) code. Was hoping there was an easier way to track changes. This is a simple case, but there could have been more complicated logic that would result in me having to set the changed flag.

2
if item.id in self.my_dict { self.my_dict[item.id] = item; self.notify() }? (excuse the braces and semicolons, but comments eat linebreaks) - user395760

2 Answers

13
votes

You can derive from the dict class and add a callback on any changes. This requires to overwrite any methods that change the dictionary:

class NotifyDict(dict):
    __slots__ = ["callback"]
    def __init__(self, callback, *args, **kwargs):
        self.callback = callback
        dict.__init__(self, *args, **kwargs)
    def _wrap(method):
        def wrapper(self, *args, **kwargs):
            result = method(self, *args, **kwargs)
            self.callback()
            return result
        return wrapper
    __delitem__ = _wrap(dict.__delitem__)
    __setitem__ = _wrap(dict.__setitem__)
    clear = _wrap(dict.clear)
    pop = _wrap(dict.pop)
    popitem = _wrap(dict.popitem)
    setdefault = _wrap(dict.setdefault)
    update =  _wrap(dict.update)
1
votes

Subclass dict and override __setitem__, making sure to call dict.__setitem__ after your stuff to ensure the item actually gets saved.

class Notifier(dict):
    def __setitem__(self, key, value):
        print 'Something is being set!'
        dict.__setitem__(self, key, value)