tags:

views:

179

answers:

4

I want 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?

A: 

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.

steveha
+2  A: 

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

Corbin March
+4  A: 

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
Nick Craig-Wood
Nice. In the mean time I implemented it myself in a way very similar to yours. The difference is that I used hash. Why did you use pickle? Is it better?
cool-RR
I think you'll find that the hash might not change if the object changes, but the pickle definitely will.
Nick Craig-Wood
Okay, thanks for the tip, I'll start using pickles.
cool-RR
+1  A: 

I am stole idea from Nick Craig-Wood, and change it to Mix-Class. Come out more easyly using, as for me

from cPickle import dumps

#base class for monitoring changes
class ChangesMonitor:
    _cm_last_dump = None
    def is_chaged(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 common class
    class MyGreateObject(ChangesMonitor,object):
        one_val = 5
        second_val = 7
        def some_changes(self):
            self.second_val += 5

    #and testing
    my_obj = MyGreateObject()
    print my_obj.is_chaged()
    print my_obj.is_chaged()
    my_obj.some_changes()
    print my_obj.is_chaged()
    print my_obj.is_chaged()
Oduvan