2009-10-15 77 views
4

我想要一個Python對象,它可以監視自上次登錄後其他對象是否發生了更改,可能是通過存儲它們的哈希和比較來進行的。它應該是這樣的:監視對象變化的Python對象

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

你知道這樣的事嗎?

回答

6

這裏是你實現。請注意,您監視的對象必須是可哈希和可挑選的。還請注意,使用WeakKeyDictionary這意味着Monitor不會停止將被監視的對象刪除。

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 

如果你測試它像這樣

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

它打印

False 
True 
False 
+0

不錯。與此同時,我自己以一種非常類似於您的方式實現了它。不同之處在於我使用了散列。你爲什麼使用泡菜?好點嗎? – 2009-10-15 20:19:59

+0

我想你會發現,如果對象發生變化,哈希值可能不會改變,但醃菜絕對會。 – 2009-10-15 20:42:49

+0

好的,謝謝你的提示,我會開始使用泡菜。 – 2009-10-15 21:05:35

0

我還沒有聽說過這樣的事......但你可以很容易地寫出來。使用字典爲每個對象存儲名稱:散列對,然後使用pickle模塊保存字典。

2

我偷了尼克·克雷格 - 伍德的想法,並將其轉變爲混合級。對我來說,這是更容易使用:

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 
0

這是基於Oduvan的答案,但作爲裝飾,而不是實現一個混合類:

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 

注意@property能補def is_changed(self):行的前面,使得print my_obj.is_changed()將變爲print my_obj.is_changed。這可能會被認爲是更pythonic ...