By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,759 Members | 959 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,759 IT Pros & Developers. It's quick & easy.

Publish/subscribe event manager using weakrefs

P: n/a
'''

event.py

An event manager using publish/subscribe, and weakrefs.
Any function can publish any event without registering it first, and
any
object can register interest in any event, even if it doesn't exist
yet.
The event manager uses weakrefs, so lists of listeners won't stop them
from being garbage collected when they're deleted.

Any suggestions are appreciated!

Sample output:

EVENT init (0 listeners, possibly dead) ('No one is interested in this
event',)
EVENT ball (0 listeners, possibly dead) ('Look! A ball, but no one is
watching.',)
*** Fido is interested in Bone
*** Fido is interested in Ball
EVENT ball (1 listeners, possibly dead) ('Another ball! Watch, Fido!',)
*** Fido noses the ball forward
*** Fido is dead.
EVENT ball (1 listeners, possibly dead) ('No one is watching because
Fido is dead.',)
Removing <weakref at 00CE9F90; dead> from ball
*** Snowball is interested in Ball
*** Snowball is interested in Yarn
*** Snowball is interested in Fluffy chick
*** Spot is interested in Bone
*** Spot is interested in Ball
EVENT bone (2 listeners, possibly dead) ('Only dogs eat bones.',)
Removing <weakref at 00CE9F90; dead> from bone
*** Spot slobbers on the bone
EVENT ball (2 listeners, possibly dead) ('Cats and dogs both love this
one!',)
*** Snowball chases the ball
*** Spot noses the ball forward
EVENT yarn (1 listeners, possibly dead) ('ball of pink yarn',)
*** Snowball bats at the yarn.
EVENT raking (0 listeners, possibly dead) ('Humans working in the
yard',)
EVENT fluffychick (1 listeners, possibly dead) ('Ooh, how cute! An
Easter leftover walking in the yard.',)
*** Snowball eats the fluffy chick.
Removing listener {'name': 'Snowball'} from event fluffychick
EVENT fluffychick (0 listeners, possibly dead) ('The cat is full and no
longer interested in chicks.',)
*** Snowball is dead.
*** Spot is dead.
EVENT ball (2 listeners, possibly dead) ('Ball anyone? Fluffy? Spot?
Fido?',)
Removing <weakref at 00CE9FC0; dead> from ball
Removing <weakref at 00CFA030; dead> from ball
Done!


'''

import weakref

_events = {}

def Subscribe(eventname, self):
" Subscribe to an event, even if it doesn't exist yet."
eventname = eventname.lower()
eventname = eventname.replace(' ', '')
if not eventname in _events:
_events[eventname] = []
listeners = _events[eventname]
obj = weakref.ref(self)
if not obj in listeners:
listeners.append(obj)

def Unsubscribe(eventname, self):
" Unsubscribe from an event, even if it never existed."
eventname = eventname.lower()
eventname = eventname.replace(' ', '')
if not eventname in _events:
return
listeners = _events[eventname]
obj = weakref.ref(self)
if obj in listeners:
print "Removing listener %s from event %s" % (str(self),
eventname)
listeners.remove(obj)

def Raise(eventname, *args, **kwargs):
" Publish an event, no need to register it first."
eventname = eventname.lower()
eventname = eventname.replace(' ', '')
if not eventname in _events:
_events[eventname] = []
listeners = _events[eventname]
print "EVENT %s (%d listeners, possibly dead) %s" % (eventname,
len(listeners), str(args))
i = 0
while i < len(listeners):
obj = listeners[i]
listener = obj()
if listener:
fnname = 'On' + eventname[0].upper() +
eventname[1:].lower()
fn = getattr(listener, fnname, None)
if fn == None:
fn = getattr(listener, 'OnEvent')
fn(eventname, *args, **kwargs)
i += 1
else:
print "Removing %s from %s" % (str(obj), eventname)
listeners.remove(obj)
class Listener:
'''
Objects that want to be notified of events.
They should have an 'OnEventname' function for
every event they're interested in, or a single
function called 'OnEvent' to receive all events.
'''
_listen = []
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
for eventname in self._listen:
Subscribe(eventname, self)
print "*** %s is interested in %s" % (self.name, eventname)
def OnEvent(self, eventname, *args, **kwargs):
print "*** %s(%s, %s)" % (eventname, str(args), str(kwargs))
def __str__(self):
return str(self.__dict__)
def __del__(self):
print "*** %s is dead." % self.name


def main():

class Dog(Listener):
name = 'Dog'
_listen = ['Bone', 'Ball']
def OnEvent(self, eventname, *args, **kwargs):
if eventname == 'bone':
print "*** %s slobbers on the bone" % self.name
elif eventname == 'ball':
print "*** %s noses the ball forward" % self.name

class Cat(Listener):
name = 'Cat'
_listen = ['Ball', 'Yarn', 'Fluffy chick']
def OnBall(self, *args, **kwargs):
print "*** %s chases the ball" % self.name
def OnYarn(self, *args, **kwargs):
print "*** %s bats at the yarn." % self.name
def OnFluffychick(self, *args, **kwargs):
print "*** %s eats the fluffy chick." % self.name

Raise('INIT', 'No one is interested in this event')
Raise('BALL', 'Look! A ball, but no one is watching.')
dog = Dog(name = 'Fido')
Raise('BALL', 'Another ball! Watch, Fido!')
del dog
Raise('BALL', 'No one is watching because Fido is dead.')
cat = Cat(name = 'Snowball')
dog = Dog(name = 'Spot')
Raise('BONE', "Only dogs eat bones.")
Raise('BALL', "Cats and dogs both love this one!")
Raise('YARN', "ball of pink yarn")
Raise('RAKING', 'Humans working in the yard')
Raise('Fluffy chick', 'Ooh, how cute! An Easter leftover walking in
the yard.')
Unsubscribe('fluffy chick', cat)
Raise('Fluffy chick', 'The cat is full and no longer interested in
chicks.')
del cat
del dog
Raise('BALL', 'Ball anyone? Fluffy? Spot? Fido?')
print "Done!"

if __name__ == '__main__':
main()

Feb 15 '06 #1
Share this question for a faster answer!
Share on Google+

This discussion thread is closed

Replies have been disabled for this discussion.