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()