Axel - Python events handling


Version 0.0.5
Last updated: March 9th, 2016

Description, Features & Download

Axel is a very small Python library, inspired by C# events, that allows an easy and elegant event handling.



The latest version of Axel can be downloaded from


from axel import Event
event = Event()
def on_event(*args, **kwargs):
    return (args, kwargs)

event += on_event                        # handler registration
print(event(10, 20, y=30))        
>> ((True, ((10, 20), {'y': 30}), <function on_event at 0x00BAA270>),)
event -= on_event                        # handler is unregistered
print(event(10, 20, y=30))     
>> None
class Mouse(object):
    def __init__(self): = Event(self) += self.on_click

    def on_click(self, sender, *args, **kwargs):
        assert isinstance(sender, Mouse), 'Wrong sender'
        return (args, kwargs)

mouse = Mouse()
print(, 20))
>> ((True, ((10, 20), {})
>> <bound method Mouse.on_click of <__main__.Mouse object at 0x00B6F470>>),) -= mouse.on_click
print(, 20))
>> None

Events can trigger further events, if necessary:
from axel import Event

class Mouse(object):
    def __init__(self): = Event(self)        
        self.move = Event(self)
        += self.on_click
        self.move += self.on_move
        += self.move     # triggers event 'move' on call
    def on_click(self, sender, x, y):
        assert isinstance(sender, Mouse)
        return ('on_click', x, y)

    def on_move(self, sender, x, y):
        assert isinstance(sender, Mouse)
        return ('on_move', x, y)   

m = Mouse()
res =, 20)
>>  ('on_click', 10, 20),
>>  <bound method Mouse.on_click of <__main__.Mouse object at 0x00BBCED0>>),
>> (True,
>>  ((True,
>>    ('on_move', 10, 20),
>>    <bound method Mouse.on_move of <__main__.Mouse object at 0x00BBCED0>>),),
>>  <axel.axel.Event object at 0x00BBCF50>))       

The Event class

Constructor's arguments

Event is the core class of the implementation. The usage is very straightforward and all the features are controlled by the constructor's arguments. The arguments are: Although most of the arguments are Event related, there is a way to pass two arguments when a handler is registered: one will determine if the execution result of the current handler will be cached; the second one will allocate a predefined time interval for execution.
event += handler or
event += (handler, True, .3) or  
event += {'handler':handler, 'memoize':True, 'timeout':.3}
Upon the call of the event, the execution results of registered handlers are returned as a tuple. The content of the tuple is determined by the Event arguments and the result itself. For each executed handler, the tuple will contain an entry with the following structure:
(flag, result, handler)
(True, result, handler),        # success
(False, exc_info, handler),     # error
(None, None, handler), ...      # asynchronous execution


The Event class has the follwing methods:


The following structures are used to store events, cache and return results:
hash = hash(handler)

handlers = { 
    hash : (handler, memoize, timeout),
    hash : (handler, memoize, timeout), ... 

memoize = { 
    hash : ((args, kwargs, result), (args, kwargs, result), ...), 
    hash : ((args, kwargs, result), ...), ...                       

exec_result = (
    (True, result, handler),        # success
    (False, ecx_info, handler),     # error
    (None, None, handler), ...      # asynchronous execution