Observer

#!/usr/bin/env python
#
# [SNIPPET_NAME: Observer]
# [SNIPPET_CATEGORIES: Patterns]
# [SNIPPET_DESCRIPTION: A module providing a basic implementation of the Observer pattern]
# [SNIPPET_AUTHOR: Scott Ferguson <[email protected]>]
# [SNIPPET_LICENSE: GPL]

"""This pattern is great for allowing asynchronous modules of your application to communicate
when something happens.  This is very useful in threaded GUI applications when you want a
threaded operation to alert the main UI that an operation has been performed and you have a
tangible result."""

# wikipedia: http://en.wikipedia.org/wiki/Observer_pattern

class Observer:
    """An observer simply watches a concrete subject, waiting for something to occur.
    The update() function will always be defined in the observer."""
    def update(self):
        return;

class Subject:
    """The subject is watched by one or many observers.  When something occurs within the
    subject, all observers are notified."""
    def __init__(self):
        self._observers = []

    def attach(self, observer):
        """Add a new observer to self"""
        if not observer in self._observers:
            self._observers.append(observer)

    def detach(self, observer):
        """Remove an observer from self"""
        try:
            self._observers.remove(observer)
        except ValueError:
            pass

    def notify(self, *args):
        """Notify all observers that something occurred"""
        for observer in self._observers:
            observer.update(*args)

# # # # Example Code from here on # # # #

"""In this sample code the application class creates a widget, and then fires off
an event on that widget.  It is always watching the widget, waiting for something
to occur."""

import time

class widget(Subject):
    _counter = 1

    def __init__(self, client):
        Subject.__init__(self)
        self.attach(client)
    
    def _respond(self):
        self.notify(self._counter)
        self._counter = self._counter + 1

    def wait_for_response(self):
        self._respond()
        time.sleep(2)
        self._respond()
        time.sleep(2)
        self._respond()
        time.sleep(2)
        self._respond()

class application(Observer):
    def __init__(self):
        self.button = widget(self)

    def click_widget(self):
        self.button.wait_for_response()
    
    def update(self, *args):
        print 'Updated! The subject said: %s' % args[0]

if __name__ == '__main__':
    app = application()
    app.click_widget()