Python observable implementation that supports multi-channel subscribers
Question: In a twisted application I have a series of resource controller/manager
classes that interact via the Observable pattern. Generally most observers
will subscribe to a specific channel (ex. "foo.bar.entity2") but there are a
few cases where I'd like to know about all event in a specific channel (ex.
"foo.*" ) so I wrote something like the following:

    
    
        from collections import defaultdict
    
        class SimplePubSub(object):
    
            def __init__(self):
                self.subjects = defaultdict(list)
    
    
            def subscribe(self, subject, callbackstr):
                """
                    for brevity, callbackstr would be a valid Python function or bound method but here is just a string
                """
                self.subjects[subject].append(callbackstr)
    
            def fire(self, subject):
                """
                    Again for brevity, fire would have *args, **kwargs or some other additional message arguments but not here            
                """
    
                if subject in self.subjects:
                    print "Firing callback %s" % subject
                    for callback in self.subjects[subject]:
                        print "callback %s" % callback
    
    
    
        pubSub = SimplePubSub()
        pubSub.subscribe('foo.bar', "foo.bar1")
        pubSub.subscribe('foo.foo', "foo.foo1")
    
        pubSub.subscribe('foo.ich.tier1', "foo.ich.tier3_1")
        pubSub.subscribe('foo.ich.tier2', "foo.ich.tier2_1")
        pubSub.subscribe('foo.ich.tier3', "foo.ich.tier2_1")
    
        #Find everything that starts with foo
        #say foo.bar is fired
        firedSubject = "foo.bar"
        pubSub.fire(firedSubject)
        #outputs 
        #>>Firing callback foo.bar
        #>>callback foo.bar1
    
        #but let's say I want to add a callback for everything undr foo.ich
    
        class GlobalPubSub(SimplePubSub):
    
            def __init__(self):
                self.globals = defaultdict(list)
                super(GlobalPubSub, self).__init__()
    
    
            def subscribe(self, subject, callback):
                if subject.find("*") > -1:
                    #assumes global suscriptions would be like subject.foo.* and we want to catch all subject.foo's 
                    self.globals[subject[:-2]].append(callback)
                else:
                    super(GlobalPubSub, self).subscribe(subject, callback)
    
            def fire(self, subject):
                super(GlobalPubSub, self).fire(subject)
                if self.globals:
                    for key in self.globals.iterkeys():
                        if subject.startswith(key):
                            for callback in self.globals[key]:
                                print "global callback says", callback
    
        print "Now with global subscriptions"
        print
        pubSub = GlobalPubSub()
        pubSub.subscribe('foo.bar', "foo.bar1")
        pubSub.subscribe('foo.foo', "foo.foo1")
    
        pubSub.subscribe('foo.ich.tier1', "foo.ich.tier3_1")
        pubSub.subscribe('foo.ich.tier2', "foo.ich.tier2_1")
        pubSub.subscribe('foo.ich.tier3', "foo.ich.tier2_1")
        pubSub.subscribe("foo.ich.*", "All the ichs, all the time!")
    
        #Find everything that starts with foo.ich
        firedSubject = "foo.ich.tier2"
        pubSub.fire(firedSubject)
        #outputs 
        #>>Firing callback foo.bar
        #>>callback foo.bar1
        #>>Now with global subscriptions
        #
        #>>Firing callback foo.ich.tier2
        #>>callback foo.ich.tier2_1
        #>>global callback says All the ichs, all the time!
    

Is this as good as it gets without resorting to some sort of exotic construct
( tries for example )? I'm looking for an affirmation that I'm on the right
track or a better alternative suggestion on a global subscription handler
that's pure python ( no external libraries or services ).


Answer: This looks like you are on the right track to me. I was using
[PyPubSub](http://pubsub.sourceforge.net/) with a wxPython app for a bit, and
then ended up implementing my own "more simple" version that, at its root,
looks very similar to what you've done here except with a few more bells and
whistles that you'd probably end up implementing as you fill out your
requirements.

The answer given [here](http://stackoverflow.com/questions/1904351/python-
observer-pattern-examples-tips) is also lot like what you have done as well.

This [answer](http://stackoverflow.com/questions/1092531/event-system-in-
python) goes into examples that are a bit different approach.

There are a number existing libraries besides
[PyPubSub](http://pubsub.sourceforge.net/) out there, such as
[pydispatch](http://pydispatcher.sourceforge.net/) and
[blinker](http://discorporate.us/projects/Blinker/), that might be worth
looking at for reference or ideas.

