I wrote this in Signal/Slot implementation last night for use in a project I'm working on. There's always another way of doing something in python, and I'm pretty clueless on a lot of the advanced python topics (itertools...). So I was wondering if any of the local GDNet gurus could critique it for me and perhaps even point out some places where there's a python construct that could be used instead of my code.
If you like what I've done, please feel free to use it yourself. Just give me some props in your source =)
"""
File: Signal.py
Author: Patrick Chasco
Created: July 26, 2005
Purpose: A signals implementation
"""
# This code is public domain with one condition: If you use it,
# please give credit to the Author in your source.
from weakref import *
import inspect
class Signal:
"""
class Signal
A simple implementation of the Signal/Slot pattern. To use, simply
create a Signal instance. The instance may be a part of a class,
global, or local; it makes no difference what scope it resides
within. Connect slots to the signal using the "connect()" method.
The slot may be a member of a class or a simple function. If the
slot is a member of a class, Signal will automatically detect when
the method's class instance has been deleted and remove it from
its list of connected slots.
"""
def __init__(self):
self.slots = []
# for keeping references to _WeakMethod_FuncHost objects.
# If we didn't, then the weak references would die for
# non-method slots that we've created.
self.funchost = []
def __call__(self, *args, **kwargs):
for i in range(len(self.slots)):
slot = self.slots
if slot != None:
slot(*args, **kwargs)
else:
del self.slots
def connect(self, slot):
self.disconnect(slot)
if inspect.ismethod(slot):
self.slots.append(WeakMethod(slot))
else:
o = _WeakMethod_FuncHost(slot)
self.slots.append(WeakMethod(o.func))
# we stick a copy in here just to keep the instance alive
self.funchost.append(o)
def disconnect(self, slot):
try:
for i in range(len(self.slots)):
wm = self.slots
if inspect.ismethod(slot):
if wm.f == slot.im_func and wm.c() == slot.im_self:
del self.slots
return
else:
if wm.c().hostedFunction == slot:
del self.slots
return
except:
pass
def disconnectAll(self):
del self.slots
del self.funchost
self.slots = []
self.funchost = []
class _WeakMethod_FuncHost:
def __init__(self, func):
self.hostedFunction = func
def func(self, *args, **kwargs):
self.hostedFunction(*args, **kwargs)
# this class was generously donated by a poster on ASPN (aspn.activestate.com)
class WeakMethod:
def __init__(self, f):
self.f = f.im_func
self.c = ref(f.im_self)
def __call__(self, *args, **kwargs):
if self.c() == None : return
self.f(self.c(), *args, **kwargs)
if __name__ == "__main__":
class Alarm:
def __init__(self):
self.SigRing = Signal()
class Sleeper:
def __init__(self, name):
self.name = name
def OnRing(self, time):
print self.name, "heard the alarm at", time
def Listener(time):
print "Listener received the signal at", time
alarm = Alarm()
patrick = Sleeper("Patrick")
katie = Sleeper("Katie")
billy = Sleeper("Billy")
print "ring patrick, katie, billy"
alarm.SigRing.connect(patrick.OnRing)
alarm.SigRing.connect(katie.OnRing)
alarm.SigRing.connect(billy.OnRing)
alarm.SigRing(time="12:00 AM")
print
print "ring katie, billy"
alarm.SigRing.disconnect(patrick.OnRing)
alarm.SigRing("12:01 AM")
print
del katie
print "ring billy"
alarm.SigRing("12:02 AM")
print
print "ring patrick, billy"
alarm.SigRing.connect(patrick.OnRing)
alarm.SigRing.connect(billy.OnRing)
alarm.SigRing("12:03 AM")
print
print "ring none"
alarm.SigRing.disconnectAll()
alarm.SigRing()
print
print "ring listener"
alarm.SigRing.connect(Listener)
alarm.SigRing("12:04 AM")
print
print "ring none"
alarm.SigRing.disconnect(Listener)
alarm.SigRing("12:05 AM")
print
print "ring patrick, katie, billy, listener"
alarm.SigRing.connect(patrick.OnRing)
alarm.SigRing.connect(billy.OnRing)
alarm.SigRing.connect(Listener)
alarm.SigRing(time="12:05 AM")
print
print "ring none"
alarm.SigRing.disconnectAll()
alarm.SigRing("12:06 AM")
print
And the result when ran:
>>> ================================ RESTART ================================
>>>
ring patrick, katie, billy
Patrick heard the alarm at 12:00 AM
Katie heard the alarm at 12:00 AM
Billy heard the alarm at 12:00 AM
ring katie, billy
Katie heard the alarm at 12:01 AM
Billy heard the alarm at 12:01 AM
ring billy
Billy heard the alarm at 12:02 AM
ring patrick, billy
Patrick heard the alarm at 12:03 AM
Billy heard the alarm at 12:03 AM
ring none
ring listener
Listener received the signal at 12:04 AM
ring none
ring patrick, billy, listener
Patrick heard the alarm at 12:05 AM
Billy heard the alarm at 12:05 AM
Listener received the signal at 12:05 AM
ring none
>>>
[Edited by - smr on July 27, 2005 9:36:54 AM]