[Python-Dev] Generic notifier module

Ka-Ping Yee ping@lfw.org
Wed, 19 Apr 2000 10:25:12 -0700 (PDT)


On Wed, 19 Apr 2000, Ka-Ping Yee wrote:
>     object.send(message, **args) - Call all callbacks registered on
>         object for message, in reverse order of registration, passing
>         along message and **args as arguments to each callback.

One revision to the above: callbacks should get the sender of the
message passed in as well as the message.  The tweaked module follows.


-------- snip snip ---------------------------------- notifier.py --------

# If a callback returns BREAK, no more callbacks are called.
BREAK = "break"

# This number goes up every time a callback is added.
serial = 0

# This dictionary maps callback functions to serial numbers.
callbacks = {}

def recipients(sender, message):
    """Return a list of (serial, callback) pairs for all the callbacks
    on this message and its base classes."""
    key = (sender, message)
    if callbacks.has_key(key):
        list = map(lambda (k, v): (v, k), callbacks[key].items())
    else:
        list = []
    if hasattr(message, "__bases__"):
        for base in message.__bases__:
            list.extend(recipients(sender, base))
    return list

class Notifier:
    """Mix in this class to provide notifier functionality on your objects.
    On a notifier object, use the 'notify' and 'denotify' methods to register
    or unregister callbacks on messages, and use the 'send' method to send a
    message from the object."""

    def send(self, message, **args):
        """Call any callbacks registered on this object for the given message.
        If message is a class or instance, callbacks registered on the class
        or any base class are called.  Otherwise callbacks registered on a
        message of the same value (compared by hash) are called.  The message
        and any extra keyword arguments are passed along to each callback."""
        if hasattr(message, "__class__"):
            message = message.__class__
        recip = recipients(self, message)
        recip.sort()
        recip.reverse()
        for serial, callback in recip:
            if callback(self, message, **args) == BREAK: return

    def notify(self, message, callback):
        """Register a callback on this object for a given message.  The
        message should be a class (not an instance) or a hashable object."""
        key = (self, message)
        if not callbacks.has_key(key):
            callbacks[key] = {}
        callbacks[key][callback] = serial

    def denotify(self, message, callback=None):
        """Unregister a particular callback or all existing callbacks on
        this object for a given message.  The message should be a class
        (not an instance) or a hashable object."""
        key = (self, message)
        if callbacks.has_key(key):
            if callback is None:
                del callbacks[key]
            elif callbacks[key].has_key(callback):
                del callbacks[key][callback]

-------- snip snip ---------------------------------- notifier.py --------


-- ?!ng

"Je n'aime pas les stupides garçons, même quand ils sont intelligents."
    -- Roople Unia