Events - Design Patterns

Gianmaria Iaculo - NVENTA gianmaria at hotmail.com
Fri Nov 30 15:20:59 CET 2007


Hi there,
i found a nice article about a custom implementation of events by Duncan 
Booth here:

http://www.suttoncourtenay.org.uk/duncan/accu/pythonpatterns.html#observer


The code is here:

STEP 1) Define a Delegate Class

class Delegate:
    '''Handles a list of methods and functions
    Usage:
        d = Delegate()
        d += function    # Add function to end of delegate list
        d(*args, **kw)   # Call all functions, returns a list of results
        d -= function    # Removes last matching function from list
        d -= object      # Removes all methods of object from list
    '''
    def __init__(self):
        self.__delegates = []

    def __iadd__(self, callback):
        self.__delegates.append(callback)
        return self

    def __isub__(self, callback):
        # If callback is a class instance,
        # remove all callbacks for that instance
        self.__delegates = [ cb
            for cb in self.__delegates
                if getattr(cb, 'im_self', None) != callback]

        # If callback is callable, remove the last
        # matching callback
        if callable(callback):
            for i in range(len(self.__delegates)-1, -1, -1):
                if self.__delegates[i] == callback:
                    del self.__delegates[i]
                    return self
        return self

    def __call__(self, *args, **kw):
        return [ callback(*args, **kw)
            for callback in self.__delegates]STEP 2) Define the Event 
Classclass Event(property):
    '''Class event notifier
    Usage:
        class C:
            TheEvent = Event()
            def OnTheEvent(self):
                self.TheEvent(self, context)

        instance = C()
        instance.TheEvent += callback
        instance.OnTheEvent()
        instance.TheEvent -= callback
    '''
    def __init__(self):
        self.attrName = attrName = "__Event_" + str(id(self))
        def getEvent(subject):
            if not hasattr(subject, attrName):
                setattr(subject, attrName, Delegate())
            return getattr(subject, attrName)
        super(Event, self).__init__(getEvent)

    def call(self, subject, *args, **kw):
        if hasattr(subject, self.attrName):
            getattr(subject, self.attrName)(subject, *args, **kw)

STEP 3) Use this logic in an object (ObjectA)class ClockTimer:
        def GetHour(self):
                return self._hour
        def GetMinute(self):
                return self._minute
        def GetSecond(self):
                return self._second

        TickEvent = Event()
        def OnTick(self):
                ClockTimer.TickEvent.call(self, self.GetHour(),
                        self.GetMinute(), self.GetSecond())

        def Tick(self):
                # update internal time-keeping state
                # ...
                self.OnTick()
STEP 4) Subscribe the ObjectA Event and react...class DigitalClock(Widget):
        def __init__(self, clockTimer):
                self.__subject = clockTimer
                clockTimer.TickEvent += self.Update

        def close(self):
                self.__subject.TickEvent -= self.Update

        def Update(self, subject, hour, min, sec):
                self.displayedTime = (hour, min, sec)
                self.Draw()

        def Draw(self):
                # draw the digital clock
I've tried to use it but i  failed. From mypoint of view my event is never 
been fired and it seem that my event subscription is not accepted and my 
OnTick Event never raise to execute the Update method,i've made some changes 
to the original code.. jjust inserted a timer to have this event fired many 
times:class ClockTimer:        _hour = 1    _minute = 1    _second = 1 
_timer = Timers.timer(0)        def __init__(self): 
self._timer.start(10)                while 1: 
if(self._timer.isexpired()):                self._hour = self._hour + 1 
self._minute = self._minute +1                self._second = self._second +1 
self.Tick()                self._timer.start(10) 
def getHour(self):        return self._hour        def getMinutes(self): 
return self._minute        def getSecond(self):        return self._second 
TickEvent = Event()        def OnTick(self): 
ClockTimer.TickEvent.call(self, self.getHour(), self.getMinutes(), 
self.getSecond())        def Tick(self):        print "Tick in CLockTimer" 
self.OnTick()and a little modification to the object that uses this 
event:class DigitalClock():        clockTimer = ClockTimer()        def 
__init__(self):        clockTimer.TickEvent += self.update            def 
close(self):        self.__subject.TickEvent -= self.update        def 
update(self, subject, hour, min, sec):        print hour        print min 
print secthe code is really eas as you can see... so in the main i added 
this simpleline of code...c = DigitalClock()but nothing really happen... i'm 
sure i'm going wrong somewhere.. but cant understand where...any Idea???I've 
tried to ask to Duncan directly by mail.. but the reported mail address is 
no more valid...Someone used this?? Someone uses an other way for events??? 
Regards,Gianmaria 




More information about the Python-list mailing list