Event system in Python


What event system for Python do you use? I'm already aware of pydispatcher, but I was wondering what else can be found, or is commonly used?

I'm not interested in event managers that are part of large frameworks, I'd rather use a small bare-bones solution that I can easily extend.

7/7/2009 2:00:51 PM

Accepted Answer

Wrapping up the various event systems that are mentioned in the answers here:

The most basic style of event system is the 'bag of handler methods', which is a simple implementation of the Observer pattern. Basically, the handler methods (callables) are stored in an array and are each called when the event 'fires'.

  • zope.event shows the bare bones of how this works (see Lennart's answer). Note: this example does not even support handler arguments.
  • LongPoke's 'callable list' implementation shows that such an event system can be implemented very minimalistically by subclassing list.
  • spassig's EventHook (Michael Foord's Event Pattern) is a straightforward implementation.
  • Josip's Valued Lessons Event class is basically the same, but uses a set instead of a list to store the bag, and implements __call__ which are both reasonable additions.
  • PyNotify is similar in concept and also provides additional concepts of variables and conditions ('variable changed event').
  • axel is basically a bag-of-handlers with more features related to threading, error handling, ...

The disadvantage of these event systems is that you can only register the handlers on the actual Event object (or handlers list). So at registration time the event already needs to exist.

That's why the second style of event systems exists: the publish-subscribe pattern. Here, the handlers don't register on an event object (or handler list), but on a central dispatcher. Also the notifiers only talk to the dispatcher. What to listen for, or what to publish is determined by 'signal', which is nothing more than a name (string).

  • blinker has some nifty features such as automatic disconnection and filtering based on sender.
  • PyPubSub at first sight seems to be pretty straightforward.
  • PyDispatcher seems to emphasize flexibility with regards to many-to-many publication etc.
  • louie is a reworked PyDispatcher "providing plugin infrastructure including Twisted and PyQt specific support". It seems to have lost maintenance after January 2016.
  • django.dispatch is a rewritten PyDispatcher "with a more limited interface, but higher performance".
  • Qt's Signals and Slots are available from PyQt or PySide. They work as callback when used in the same thread, or as events (using an event loop) between two different threads. Signals and Slots have the limitation that they only work in objects of classes that derive from QObject.

Note: threading.Event is not an 'event system' in the above sense. It's a thread synchronization system where one thread waits until another thread 'signals' the Event object.

Note: not yet included above are pypydispatcher, python-dispatch and the 'hook system' of pluggy might be of interest as well.

11/15/2018 12:53:22 PM

I've been doing it this way:

class Event(list):
    """Event subscription.

    A list of callable objects. Calling an instance of this will cause a
    call to each item in the list in ascending order by index.

    Example Usage:
    >>> def f(x):
    ...     print 'f(%s)' % x
    >>> def g(x):
    ...     print 'g(%s)' % x
    >>> e = Event()
    >>> e()
    >>> e.append(f)
    >>> e(123)
    >>> e.remove(f)
    >>> e()
    >>> e += (f, g)
    >>> e(10)
    >>> del e[0]
    >>> e(2)

    def __call__(self, *args, **kwargs):
        for f in self:
            f(*args, **kwargs)

    def __repr__(self):
        return "Event(%s)" % list.__repr__(self)

However, like with everything else I've seen, there is no auto generated pydoc for this, and no signatures, which really sucks.

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow