|
Demonstration of Weak Reference Extension Module |
The following listing demonstrates a simple use of weakref module:
Python 2.0b2 (#6, Sep 26 2000, 14:59:21) [MSC 32 bit (Intel)] on win32 Type "copyright", "credits" or "license" for more information. >>> import weakref >>> class Foo: pass ... >>> f = Foo () >>> wr = weakref.new (f) >>> wr A weak reference to an object of type 'instance'. >>> f1 = wr.newref () >>> f1 <__main__.Foo instance at 0081B63C> >>> f1 == f 1 >>> del f1 >>> del f >>> wr A stale weak reference. >>> type(wr.newref ())The following listing demonstrates the circular reference problem:(type, 'None')
1 # !/usr/local/bin/python 2 # 3 # Filename: circref_demo.py 4 # Copyright (c) Alex Shindich, 2000 5 # Author: Alex Shindich 6 # License: The author is making this software available on an "AS IS" basis. 7 # There are no warranties regarding this software. Use it at your own risk! 8 # Permission to use, copy, modify, and distribute this software and its 9 # documentation for any purpose and without fee is hereby granted without 10 # any restrictions. 11 # 12 # Purpose: This program demonstrates the circular reference problem. 13 14 class Subject: 15 """This class implements a very simple subject for observer pattern.""" 16 17 def __init__ (self): 18 self.__observers = [] 19 20 def addObserver (self, observer): 21 if observer.notify not in self.__observers: 22 self.__observers.append (observer.notify) 23 print "Added observer: %s" % str(observer) 24 25 def removeObserver (self, observer): 26 if observer.notify in self.__observers: 27 print "Removed observer: %s" % str(observer) 28 self.__observers.remove (observer.notify) 29 else: 30 print "Cannot remove an unknown observer: %s" % str(observer) 31 32 def notifyAll (self, msg): 33 if self.__observers: 34 for notify in self.__observers: 35 notify (msg) 36 else: 37 print "No observers to notify." 38 39 class Observer: 40 """This class implements a very simple observer for observer pattern.""" 41 42 def __init__(self, subject): 43 self.__subject = subject 44 self.__subject.addObserver (self) 45 46 def __del__ (self): 47 self.__subject.removeObserver (self) 48 print "Observer destroyed: %s" % str(self) 49 50 def notify (self, msg): 51 print "Notification received from the subject:\n\t'%s'" % msg 52 53 def main (): 54 # Create the subject 55 sub = Subject () 56 # Create an observer 57 obs = Observer (sub) 58 # Notify all the observers 59 sub.notifyAll ("Python rules!") 60 # Delete an observer 61 del obs 62 # Notify all the observers 63 sub.notifyAll ("There shouldn't be any observers at this point.") 64 65 66 if __name__ == '__main__': 67 main () |
Added observer: <__main__.Observer instance at 007F886C> Notification received from the subject: 'Python rules!' Notification received from the subject: 'There shouldn't be any observers at this point.'
The following listing demonstrates how this problem can be solved using weak
references:
1 # !/usr/local/bin/python 2 # 3 # Filename: circref_demo.py 4 # Copyright (c) Alex Shindich, 2000 5 # Author: Alex Shindich 6 # License: The author is making this software available on an "AS IS" basis. 7 # There are no warranties regarding this software. Use it at your own risk! 8 # Permission to use, copy, modify, and distribute this software and its 9 # documentation for any purpose and without fee is hereby granted without 10 # any restrictions. 11 # 12 # Purpose: This program demonstrates the use of weakref module. 13 14 try: 15 import weakref 16 except ImportError, ex: 17 print ex 18 print "Please make sure that weakref module is in the Python library path." 19 import sys 20 sys.exit (0) 21 22 23 24 class Subject: 25 """This class implements a very simple subject for observer pattern.""" 26 27 class Callback: 28 """This class represents an observer callback reference.""" 29 30 def __init__ (self, instanceMethod): 31 self.__func = instanceMethod.im_func 32 self.__ob_self = weakref.new (instanceMethod.im_self) 33 34 def __call__ (self, *args): 35 ob_self = self.__ob_self.newref () 36 func = self.__func 37 if ob_self and func: 38 apply (func, (ob_self,) + args) 39 40 def __init__ (self): 41 self.__observers = {} 42 43 def addObserver (self, observer): 44 # Create a weak reference that we will use for dictionary 45 wr_observer = weakref.new (observer) 46 # Check to see if the weak reference is in the dictionary already 47 if not self.__observers.has_key (wr_observer): 48 # Create a callback instance and add it to the dictionary 49 cb = Subject.Callback (observer.notify) 50 self.__observers[wr_observer]= cb 51 print "Added observer: %s" % str(observer) 52 53 def removeObserver (self, observer): 54 # Create a weak reference that we will use for dictionary 55 wr_observer = weakref.new (observer) 56 # Check to see if the weak reference is in the dictionary 57 if self.__observers.has_key (wr_observer): 58 print "Removed observer: %s" % str(observer) 59 # Delete the weak reference from the map 60 del self.__observers[wr_observer] 61 else: 62 print "Cannot remove an unknown observer: %s" % str(observer) 63 64 def notifyAll (self, msg): 65 if self.__observers: 66 for notify in self.__observers.values (): 67 notify (msg) 68 else: 69 print "No observers to notify." 70 71 class Observer: 72 """This class implements a very simple observer for observer pattern.""" 73 74 def __init__(self, subject): 75 self.__subject = subject 76 self.__subject.addObserver (self) 77 78 def __del__ (self): 79 self.__subject.removeObserver (self) 80 print "Observer destroyed: %s" % str(self) 81 82 def notify (self, msg): 83 print "Notification received from the subject:\n\t'%s'" % msg 84 85 def main (): 86 # Create the subject 87 sub = Subject () 88 # Create an observer 89 obs = Observer (sub) 90 # Notify all the observers 91 sub.notifyAll ("Python rules!") 92 # Delete an observer 93 del obs 94 # Notify all the observers 95 sub.notifyAll ("There shouldn't be any observers at this point.") 96 97 if __name__ == '__main__': 98 main () |
The following is the output of this program:
Added observer: <__main__.Observer instance at 008254EC> Notification received from the subject: 'Python rules!' Removed observer: <__main__.Observer instance at 008254EC> Observer destroyed: <__main__.Observer instance at 008254EC> No observers to notify.
Note that the problem is really solved through the use of Callback class.