开发者

Python object that monitors changes in objects

I wa开发者_如何学Gont a Python object that will monitor whether other objects have changed since the last time they were checked in, probably by storing their hash and comparing. It should behave sort of like this:

>>> library = Library()
>>> library.is_changed(object1)
False
>>> object1.change_somehow()
>>> library.is_changed(object1)
True
>>> library.is_changed(object1)
False

Do you know of anything like that?


Here is an implementation for you. Note that the objects you monitor must be hashable and picklable. Note also the use of a WeakKeyDictionary which means that the Monitor won't stop the monitored objects from being deleted.

from weakref import WeakKeyDictionary
from cPickle import dumps

class Monitor():
    def __init__(self):
        self.objects = WeakKeyDictionary()
    def is_changed(self, obj):
        current_pickle = dumps(obj, -1)
        changed = False
        if obj in self.objects:
            changed = current_pickle != self.objects[obj]
        self.objects[obj] = current_pickle
        return changed

class MyObject():
    def __init__(self):
        self.i = 1
    def change_somehow(self):
        self.i += 1

If you test it like this

object1 = MyObject()
monitor = Monitor()
print monitor.is_changed(object1)
object1.change_somehow()
print monitor.is_changed(object1)
print monitor.is_changed(object1)

It prints

False
True
False


It sounds like you're describing the observer pattern. Check here:

  • http://rudd-o.com/projects/python-observable/
  • Twisted observable
  • http://radio.weblogs.com/0124960/2004/06/15.html#a30 - includes explanation


I stole the idea from Nick Craig-Wood, and changed it to a Mix-Class. For me, this is easier to use:

from cPickle import dumps

#base class for monitoring changes
class ChangesMonitor:
    _cm_last_dump = None
    def is_changed(self):
        prev_dump = self._cm_last_dump
        self._cm_last_dump = None
        cur_dump = dumps(self, -1)
        self._cm_last_dump = cur_dump
        return (prev_dump is not None) and (prev_dump != cur_dump)

if __name__ == '__main__':
    print 'Test Example'

    #mix monitoring class with your regular class
    class MyGreatObject(ChangesMonitor, object):
        one_val = 5
        second_val = 7
        def some_changes(self):
            self.second_val += 5

    #and testing
    my_obj = MyGreatObject()
    print my_obj.is_changed() #False
    print my_obj.is_changed() #False
    my_obj.some_changes()
    print my_obj.is_changed() #True
    print my_obj.is_changed() #False


I haven't heard of anything like this... but you could write it pretty easily. Use a dictionary to store a name:hash pair for each object, then use the pickle module to save the dictionary.


This is based on Oduvan's answer, but implemented as a decorator instead of a mix-in class:

from cPickle import dumps

#decorator for monitoring changes
def ChangesMonitor(cls):

    def is_changed(self):
        prev_dump = self._cm_last_dump
        self._cm_last_dump = None
        cur_dump = dumps(self, -1)
        self._cm_last_dump = cur_dump
        return (prev_dump is not None) and (prev_dump != cur_dump)

    cls.is_changed = is_changed
    cls._cm_last_dump = None
    return cls

print 'Test Example'

#decorate your common class
@ChangesMonitor
class MyGreatObject(object):
    one_val = 5
    second_val = 7
    def some_changes(self):
        self.second_val += 5

#and testing
my_obj = MyGreatObject()
print my_obj.is_changed() #False
print my_obj.is_changed() #False
my_obj.some_changes()
print my_obj.is_changed() #True
print my_obj.is_changed() #False

Note that @property could be added in front of the def is_changed(self): line such that print my_obj.is_changed() would become print my_obj.is_changed. This might be considered more pythonic...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜