Welcome, guest | Sign In | My Account | Store | Cart
import copy

class Subject:
    def __init__(self, excluded):
        # excluded is a list of attribute names
        
        # who should be notified
        self.__dict__['_observers'] = []
        
        # which attrs should not trigger a notification
        # obviously it can be done the other way round if needed
        # i.e.which attrs trigger a notification 
        self.__dict__['_excluded_attrs'] = copy.copy(excluded)

    def __setattr__(self, attrname, value):
        # set the attribute
        self.__dict__[attrname] = value
        # if the attribute triggers a notification
        if not attrname in self._excluded_attrs:
            # notify observers
            self.notify(attrname, value)

    def attach(self, observer):
        if not observer in self._observers:
            self._observers.append(observer)

    def detach(self, observer):
        try:
            self._observers.remove(observer)
        except ValueError:
            pass

    def notify(self, attrname, value):
        for observer in self._observers:
            observer.update(self, attrname, value)

# Example usage
class Data(Subject):
    def __init__(self, excluded=[]):
        # pass up the attrs to be excluded from notification
        Subject.__init__(self, excluded)

class Observer1:
    def update(self, subject, attrname, value):
        print 'Observer1: Subject %s has updated attr %s to %s' % (subject.name, attrname, value)

class Observer2:
    def update(self, subject, attrname, value):
        print 'Observer2: Subject %s has updated attr %s to %s' % (subject.name, attrname, value)

# Example
def main():
    print "Creating data1 without notification for attrs name & surname"
    data1 = Data(excluded=['name','surname'])
    print "Creating data2 without notification for attr age"
    data2 = Data(excluded=['age'])

    obs1 = Observer1()
    data1.attach(obs1)
    data1.attach(obs1)

    obs2 = Observer2()
    data2.attach(obs2)
    data2.attach(obs2)

# now try it
# you can set any attribute directly
    print "Setting data1.name=Heather - Notification unnecessary"
    data1.name = 'Heather'
    print "Setting data1.num=333 - Notification expected"
    data1.num = 333;

    print "Setting data2.name=Molly - Notification expected"
    data2.name = 'Molly'
    print "Setting data2.age=28 - Notification unnecessary"
    data2.age = 28
    print "Setting data2.eyecolor=blue - Notification expected"
    data2.eyecolor='blue';

if __name__ == '__main__':
    main()

Diff to Previous Revision

--- revision 1 2013-03-07 11:49:29
+++ revision 2 2013-03-09 10:03:10
@@ -1,12 +1,24 @@
+import copy
+
 class Subject:
-    def __init__(self):
-        self._observers = []
+    def __init__(self, excluded):
+        # excluded is a list of attribute names
+        
+        # who should be notified
+        self.__dict__['_observers'] = []
+        
+        # which attrs should not trigger a notification
+        # obviously it can be done the other way round if needed
+        # i.e.which attrs trigger a notification 
+        self.__dict__['_excluded_attrs'] = copy.copy(excluded)
 
-    def __setattr__(self,attrname, value):
+    def __setattr__(self, attrname, value):
         # set the attribute
         self.__dict__[attrname] = value
-        # and now notify observers
-        self.notify()
+        # if the attribute triggers a notification
+        if not attrname in self._excluded_attrs:
+            # notify observers
+            self.notify(attrname, value)
 
     def attach(self, observer):
         if not observer in self._observers:
@@ -18,69 +30,52 @@
         except ValueError:
             pass
 
-    def notify(self, modifier=None):
+    def notify(self, attrname, value):
         for observer in self._observers:
-            if modifier != observer:
-                observer.update(self)
-
+            observer.update(self, attrname, value)
 
 # Example usage
 class Data(Subject):
-    def __init__(self, name=''):
-        Subject.__init__(self)
-        self.name = name
-        self.data = 0
+    def __init__(self, excluded=[]):
+        # pass up the attrs to be excluded from notification
+        Subject.__init__(self, excluded)
 
-    def setData(self, data):
-        self.data = data
-        # not needed anymore: self.notify()
+class Observer1:
+    def update(self, subject, attrname, value):
+        print 'Observer1: Subject %s has updated attr %s to %s' % (subject.name, attrname, value)
 
-    def getData(self):
-        return self.data
+class Observer2:
+    def update(self, subject, attrname, value):
+        print 'Observer2: Subject %s has updated attr %s to %s' % (subject.name, attrname, value)
 
+# Example
+def main():
+    print "Creating data1 without notification for attrs name & surname"
+    data1 = Data(excluded=['name','surname'])
+    print "Creating data2 without notification for attr age"
+    data2 = Data(excluded=['age'])
 
-class HexViewer:
-    def update(self, subject):
-        print 'HexViewer: Subject %s has data 0x%x' % (subject.name, subject.getData())
+    obs1 = Observer1()
+    data1.attach(obs1)
+    data1.attach(obs1)
 
+    obs2 = Observer2()
+    data2.attach(obs2)
+    data2.attach(obs2)
 
-class DecimalViewer:
-    def update(self, subject):
-        print 'DecimalViewer: Subject %s has data %d' % (subject.name, subject.getData())
+# now try it
+# you can set any attribute directly
+    print "Setting data1.name=Heather - Notification unnecessary"
+    data1.name = 'Heather'
+    print "Setting data1.num=333 - Notification expected"
+    data1.num = 333;
 
-
-# Example usage...
-def main():
-    data1 = Data('Data 1')
-    data2 = Data('Data 2')
-    view1 = DecimalViewer()
-    view2 = HexViewer()
-    data1.attach(view1)
-    data1.attach(view2)
-    data2.attach(view2)
-    data2.attach(view1)
-
-# now try it like this:
-    print "Setting Data 1 = 333"
-    data1.data = 333;
-    print "Setting Data 2 = 444"
-    data2.data = 444;
-
-#    print "Setting Data 1 = 10"
-#    data1.setData(10)
-#    print "Setting Data 2 = 15"
-#    data2.setData(15)
-#    print "Setting Data 1 = 3"
-#    data1.setData(3)
-#    print "Setting Data 2 = 5"
-#    data2.setData(5)
-#    print "Detach HexViewer from data1 and data2."
-#    data1.detach(view2)
-#    data2.detach(view2)
-#    print "Setting Data 1 = 10"
-#    data1.setData(10)
-#    print "Setting Data 2 = 15"
-#    data2.setData(15)
+    print "Setting data2.name=Molly - Notification expected"
+    data2.name = 'Molly'
+    print "Setting data2.age=28 - Notification unnecessary"
+    data2.age = 28
+    print "Setting data2.eyecolor=blue - Notification expected"
+    data2.eyecolor='blue';
 
 if __name__ == '__main__':
     main()

History