Events

Introduction

This part will be about events, event systems, their implementation with their pros and cons. I have been thinking about events and event-systems for some time now. Pygame has just a basic way to deliver events, but that isn't enough for more complex code (like MVC or other structures). Pyglet on the other side has a ready to use event system which has also its quirks. Also a good tutorial is sjbrown's Guide to Writing Games. I will try to show you different aspects, issues and ways to implement an event system.
top | back to tutorials overview

Basics: Observer pattern

To start with, any event system is basically an observer pattern (observer pattern). There is the subject which can have more than one observer (also called listeners). The idea is, that when the subject changes, it will notify the observers. How the notification is done depends on the event system and there are many different ways to implement some sort of observer pattern or dispatcher. This leads to a loose coupling of the components. So lets take a look at some ways to implement an observer pattern.

Normally the binding of observers to the subjects is done at the initialize phase because there you have access to all components. But it can be done dynamically too at runtime.

Let's start with the subject. The subject has to provide a way to register and unregister the observers to that subject. The observer on the other hand should implement the observer interface. Let's look at a naive implementation:
class Subject(object):

	def __init__(self):
		self._observers = []

	def register(self, observer):
		self._observers.append(observer)

	def unregister(self, observer):
		if observer in self._observers:
			self._observers.remove(observer)

	def notify(self, event):
		for observer in self._observers:
			observer.notify(event)


class IObserver(object):

	def notify(self, event):
		raise NotImplementedError("Must subclass and overwrite me")
			
And to use this mechanism you would do something like this:
	# overwrite the observer's notify so 
	# custom code is executed
	class PrintObserver(IObserver):
		def notify(self, event):
			print "observer", self, "got event:", event

	# create a subject
	subject = Subject()

	# create two observers and register them to the subject
	observer1 = PrintObserver()
	subject.register(observer1)
	observer2 = PrintObserver()
	subject.register(observer2)

	# send an event
	subject.notify("hello")
			
Tis naive implementation has some issues like the overhead to send all events to all observers, event if they do not process this event type. I will discuss some other issues in the following sections.
top | back to tutorials overview

Issues

The naive implementation is fully functional, but may have some potential problems. You can use it as long you don't remove or add other observers from within a observer and you want your observers be kept alive through the strong reference from the subject. Following is a deeper discussion about solving this issues and some other potentially problematic things.

Order of events

The order of events is an important aspect that should be understood. Assuming we have a subject S1 and two observers O1 and O2. O1 listens to events of type A, B and C (also from O2) and O2 listens to events of type A and sends an event of type C as soon it receives a A-event. In which order will O1 get the events if S1 send the events A, B in this order? Well you guessed right in the wrong order, but why? S1 starts by sending out event A. O1 will receive it, process it and then O2 receives it. While processing it, it generates event C which is received by O1. Then B is generated by S1 and only O1 gets it. So O1 has received the events in this order: A, C, B. Maybe this order isn't desired. The only way I see to get the order A, B and then C for O1 is to use a mediator pattern and a event queue. Instead to send out the events itself (by a subject or observer), they should be queued in a event manager (which would be the mediator, also called a dispatcher sometimes) and send then out by it. In this case the event C would be queued after the event B and therefore O1 would get the order A, B and C. Be sure to understands what is going on and in which order the events will be received.

top | tutorials | downloads

Watch the iteration

When 'notify(event)' is called in the subject, it will iterate over the stored observers. But it would break if you have an observer that adds or removes observers from that subject, e.g.:
	Observer(IObserver):
		def __init__(self, subject):
			self.subject = subject
			subject.register(self)

		def notify(self, event):
			self.subject.unregister(self)
				
So the question is how to prevent the change of the list? The simplest solution I found so far, is to make a copy of the list before iterating over it:
	def notify(self, event):
		for observer in list(self._observers):
			observer.notify(event)
				
But this has the drawback that a list is copied in memory every time a event is generated. As long this waste of performance and memory isn't a concern to you, this solution is fine. But if performance matters (and in my opinion it does, an event system should have good performance) another way is needed. So I came up with a better solution that might look a bit more complicated, but does the same thing by storing the 'add'- and 'remove'-requests. Something like this:
class Subject(object):

	def __init__(self):
		self._observers = []
		# set up helper lists and a flag
		self._to_add = []
		self._to_remove = []
		self._changed = False

	def register(self, observer):
		# each observer should only be added once
		if observer not in self._observers:
			self._to_add.append(observer)
			self._changed = True

	def unregister(self, observer):
		if observer in self._observers:
			self._to_remove.append(observer)
			self._changed = True

	def notify(self, event):
		# update the changes first if necessary
		if self._changed:
			self._changed = False
			self._observers.extend(self._to_add)
			self._to_add[:] = []
			while self._to_remove:
				self._observers.remove(self._to_remove.pop())
		# call the callbacks
		for observer in self._observers:
			observer.notify(event)
				
Frankly, I haven't profiled the two versions, which I really should do, but I'm pretty sure that checking an if is faster than making a copy of the list (might depend on the size of the list).

top | tutorials | downloads

Event design

There are many ways to design the event itself. This an important part because the other parts depend on this design. The already presented observer pattern (see Basics: Observer Pattern) is basically the infrastructure to send and receive events, but the event itself could be actually anything. So if you want different types of events you might have something like this:
class Event:
	pass

class TickEvent:
	def __init__(self, dt):
		self.dt = dt

class ClickEvent:
	def __init__(self, source):
		self.source = source

class Observer(IObserver):

	def __init__(self, subject):
		self.subject = subject

	def notify(self, event):
		if isinstance(event, TickEvent):
			# do what is needed for the TickEvent here, maybe self.update()
			pass
		elif isinstance(event, ClickEvent):
			if event.source == self.subject:
				# do something
				pass
		...
				
One thing to notice is, that you get a if...elif...elif... block in the notify() method. It will have an if for each event to catch. I do not like this if...elif... thing so I would like to do it differently. A simple way would be to have different callbacks for each event-type. But then, the subject has to keep track of the different callbacks. Maybe something like this:
class Subject:

	def __init__(self):
		self._listeners = {} #{event_type:[listeners]}

	def register(self, event_type, listener):
		self._listeners.get(event_type, []).append(listener)

	def unregister(self, event_type, listener):
		listeners = self._listeners.get(event_type, [])
		if listener in listeners:
			listeners.remove(listener)

	def update(self, event_type, event):
		for listener in self._listeners.get(event_type, []):
			listener(event)
				
Since here you would register a callback rather than an observer you don't have a notify method anymore, but you have a method for each different event type you have registered (of course, you could register the same method for every event type, but that would defeat the idea). Now the if...elif... block went into the dictionary in the subject. We even can take this idea further by splitting the dictionary into single subject for each event-type. From a slightly different point of view this means that each of this object represent an event-type by itself and could therefore be called the channel or signal. A signal represents the event-type and the subject at the same time.
# this class is the event-type and the subject at the same time
# it looks very similar to the subject, but it hold listeners to only
# one event-type
class Signal:

	def __init__(self):
		self._listeners = []

	def register(self, listener):
		if listener not in self._listeners:
			self._listeners.append(listener)

	def unregister(self, listener):
		if listener in self._listeners:
			self._listener.remove(listener)

	def emit(self, *args, **kwargs):
		for listener in self._listeners:
			listener(*args, **kwargs)

# example:
class EventDispatcher:

	def __init__(self):
		self.signal_mouse_down = Signal()
		self.signal_move = Signal()
		self.signal_click = Signal()

class ClickObserver:

	def on_click(self, click_pos):
		# do something when click event is emitted
		pass

# usage
click_observer = ClickObserver()
event_dispatcher = EventDispatcher()
event_dispatcher.signal_click.register(click_observer.on_click)
				
This system does exactly the right amount of work to get the job done. It does not iterate over all observers and call notify on them, event if the observer throws away this particular event (as with using subject-observer). The only thing that could be a drawback is, that you have a method for each different event type. But in my opinion it even makes the code clearer to read. Another difference is that the data of an event is passed directly as the arguments instead of an event instance. Of course you could pass an event instance if you wish. I'm really undecided what I prefer. Each event can have a different method signature if the number of arguments differ. My point is, that there are different ways to design the handler method:
# as in observer
def handler1(event): pass

# adding sender
def handler2(sender, event): pass

# using explicit arguments
def handler3(posx, posy, button): pass

# using generic arguments
def handler4(*args, **kwargs): pass
				
Another important thing I haven't mentioned until now is the return value of the handler method. Sometimes it is convenient, if the processing stops after a certain handler call. This only can be done by a return value which is interpreted by the sender. The return value might just be True and False. When returning True, it means the event has been handled and no further processing should be done, maybe like this:
def update(self, event):
	for handler in self._handlers:
		if handler(event):
			break;
				

top | tutorials | downloads

Exceptions

Exception handling is important and until now I haven't said anything about. What if a handler raises an exception? It shouldn't or it should catch any exception. Either the event-dispatcher does not care (as in all examples until right now), so if an exception is raised, the iteration is terminated and the exception is going onw level up. Or the dispatcher does care. The question is, how should it react to an exception. Should it remove just the faulty handlers or should it stop processing. Either way a try...except block will be needed in the code.
...
# removing faulty handlers
def update1(self, event):
	for handler in self._handlers:
		try:
			handler(event)
		except:
			self._to_remove.append(handler)
...

# or just stop processing
def update2(self, event):
	try:
		for handler in self._handlers:
			handler(event)
	except:
		# log the exception, do something
		pass
				
I'm not entirely sure if exception handling should be done here and what performance effects it could have.
top | tutorials | downloads

Let the observers die

So far we have a good subject-observer implementation, but what, if we don't want a observer to stay alive, only because it is registered in one or more subjects? Well yes, you might think that a weakref is the solution. That is only partially true. As long you save references to instance of a class or unbound functions, you can use a weakref or a WeakKeyDictionary as usual.
class Subject:

	def __init__(self):
		from weakref import WeakKeyDictionary
		self._observers = WeakKeyDictionary() # the keys are weakrefs

	def register(self, observer):
		self._observers[observer] = 1

	def unregister(self, observer):
		if observer in self._observers:
			del self._observers[observer]

	def update(self, event):
		# dead observer are removed automatically, this should also
		# avoid dead references if they die while iterating (other 
		# methods might cause problems, see WeakKeyDictionary)
		for observer in self._observers:
			observer.notify(event)
				
This will let the observers die even if they are registered at a subject. But there is a little flaw in python's weakref (well, actually it's not the weakref module itself). It cannot store a weakref to a bound method. The problem is, that you get a wrapper for the bound method which is reported as dead as soon you want to use the weak reference. The trick here is to store a weak reference to the instance and generate a new call to that method using the stored data. Here is a wrapper that does that:
from weakref import ref
from new import instancemethod

class UnboundMethodWeakref:

	def __init__(self, method):
		# check that it is a bound method (use __func__, __self__ for
		# python 2.6 or python 3.0)
		if hasattr(method, 'im_func'):
			self._im_self = ref(method.im_self)
			self._im_func = method.im_func
		else:
			self._im_self = None
			self._im_func = ref(method)

	def __call__(self):
		# check if it was a bound or unbound function
		if self._im_self:
			instance = self._im_self()
			# check if the weakref is dead
			if instance :
				# return new wrapper for bound method (bound to instance)
				return instancemethod(self._im_func, instance, instance.__class__)
			return None # else dead
		else:
			# check if unbound function is alive
			if self._im_func():
				return self._im_func() # alive
			return None # dead

	def __eq__(self, other):
		# needed to compare to be able to remove same instance from a list
		return (self._im_func == other._im_func)
				
And here how you would use it:
class Subject:

	#...

	def register(self, method):
		self._callbacks.append(UnboundMethodWeakref(method)

	def update(self, event):
		# ...
		for to_remove in self._callbacks:
			for remove_t in [t for t in self._to_remove if t==to_remove]:
				self._callbacks.remove(t)

		for weak_callback in self._callbacks:
			callback = weak_callback()
			# check if callback is alive
			if callback is not None:
				callback(event)
			else:
				# remove dead reference
				# while we are iterating over the list we cannot remove it
				# directly, also we need to compare instances of 
				# UnboundMethodWeakref and remove the one that has the same
				# references saved
				self._to_remove(UnboundMethodWeakref(method))
				

top | tutorials | downloads

Don't post events for ever

...building...
top | tutorials | downloads

Concurrency

...building...
top | tutorials | downloads

Reentrant

...building...
top | tutorials | downloads

Implementations

...building...
top | back to tutorials overview

Signal (Delegate)

...building...
top | tutorials | downloads

Eventmanager / Observer

...building...
top | tutorials | downloads

Eventhandler

...building...
top | tutorials | downloads

Messages

...building...
top | tutorials | downloads

Globalsignal

...building...
top | tutorials | downloads

Mediator

...building...
top | tutorials | downloads

Actor

...building...
top | tutorials | downloads

Resources

...building...
top | tutorials | downloads