[Python-Dev] Generic notifier module

Ka-Ping Yee ping@lfw.org
Wed, 19 Apr 2000 15:14:39 -0500 (CDT)


On Wed, 19 Apr 2000, Fredrik Lundh wrote:
> 
> your notifier looks like a supercharged version of the "Observer"
> pattern [1].  here's a minimalistic observer mixin from "(the eff-
> bot guide to) Python Patterns and Idioms" [2].

Oh, yeah, "observer".  That was the other name for this mechanism
that i forgot.

> class Observable:

I'm not picky about names... anything is fine.

>     def notify(self, event):
>         for o in self.__observers or ():
>             o(event)

*Some* sort of dispatch would be nice, i think, rather than
having to check the kind of event you're getting in every callback.

Here are the three sources of "more stuff" in Notifier as opposed
to Observer:

    1.  Dispatch.  You register callbacks for particular messages
        rather than on the whole object.

    2.  Ordering.  The callbacks are always called in reverse order
        of registration, which makes BREAK meaningful.

    3.  Inheritance.  You can use a class hierarchy of messages.

I think #1 is fairly essential, and i know i've come across
situations where #3 is useful.  The need for #2 is only a conjecture
on my part.

Does anyone care about the order in which callbacks get called?

If not (and no one needs to use BREAK), we can throw out #2 and make
Notifier simpler:

    callbacks = {}

    def send(key, message, **args):
        if callbacks.has_key(key):
            for callback in callbacks[key]:
                callback(key[0], message, **args)
        if hasattr(key[1], "__bases__"):
            for base in key[1].__bases__:
                send((key[0], base), message, **args)

    class Notifier:
        def send(self, message, **args):
            if hasattr(message, "__class__"):
                send((self, message.__class__), message, **args)
            else:
                send((self, message), message, **args)

        def notify(self, message, callback):
            key = (self, message)
            if not callbacks.has_key(key):
                callbacks[key] = []
            callbacks[key].append(callback)

        def denotify(self, message, callback=None):
            key = (self, message)
            if callbacks.has_key(key):
                if callback is None:
                    del callbacks[key]
                else:
                    callbacks[key].remove(callback)


-- ?!ng