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...
精彩评论