Mostrando entradas con la etiqueta Events. Mostrar todas las entradas
Mostrando entradas con la etiqueta Events. Mostrar todas las entradas

viernes, 27 de diciembre de 2013

Event and Listeners in Python

I work with C# on Unity3d (a platform to develop videogames) and here I learned to use Events, which you implement with the famous Observer Design Pattern (you can learn more about the pattern in this great video from Derek Banas: Observer Design Pattern). Events are a great way of telling multiple objects (listeners) that a certain event of their interest has occurred without having to search for them; its computationally efficient and really dynamic.
Being Python a dynamic language I thought there would be an Event System in the standard library, but there isn't. There are packages like PyDispatcher and PyNotify but not wanting install/test them, I decided to implement my own event manager system in a very Pythonic style.
So I created the EventManager class (code at the end), and the syntax is the following:
#Create an event with no listeners assigned to it
EventManager.addEvent( eventName = [] )

#Create an event with listeners assigned to it
EventManager.addEvent( eventName = [fun1, fun2,...] )

#Create any number event with listeners assigned to them
EventManager.addEvent( eventName1 = [e1fun1, e1fun2,...], eventName2 = [e2fun1, e2fun2,...], ... )

#Add or remove listener to an existing event
EventManager.eventName += extra_fun
EventManager.eventName -= removed_fun

#Delete an event
del EventManager.eventName

#Fire the event
EventManager.eventName()
Here is an Example:
def hello(name):
    print "Hello {}".format(name)

def greetings(name):
    print "Greetings {}".format(name)

EventManager.addEvent( salute = [greetings] )
EventManager.salute += hello

print "\nInitial salute"
EventManager.salute('Oscar')

print "\nNow remove greetings"
EventManager.salute -= greetings
EventManager.salute('Oscar')
Output:
Initial salute
Greetings Oscar
Hello Oscar 
Now remove greetings
Hello Oscar
EventManger Code:
class EventManager:

    class Event:
        def __init__(self,functions):
            if type(functions) is not list:
                raise ValueError("functions parameter has to be a list")
            self.functions = functions

        def __iadd__(self,func):
            self.functions.append(func)
            return self

        def __isub__(self,func):
            self.functions.remove(func)
            return self

        def __call__(self,*args,**kvargs):
            for func in self.functions : func(*args,**kvargs)

    @classmethod
    def addEvent(cls,**kvargs):
        """
        addEvent( event1 = [f1,f2,...], event2 = [g1,g2,...], ... )
        creates events using **kvargs to create any number of events. Each event recieves a list of functions,
        where every function in the list recieves the same parameters.

        Example:

        def hello(): print "Hello ",
        def world(): print "World"

        EventManager.addEvent( salute = [hello] )
        EventManager.salute += world

        EventManager.salute()

        Output:
        Hello World
        """
        for key in kvargs.keys():
            if type(kvargs[key]) is not list:
                raise ValueError("value has to be a list")
            else:
                kvargs[key] = cls.Event(kvargs[key])

        cls.__dict__.update(kvargs)