La mejor respuesta
Según los comentarios anteriores, esta es una estrategia general. Obviamente, los detalles importan mucho, por supuesto .
Básicamente tendrás dos partes.
El objeto de evento o el « editor» es responsable de manteniendo una lista de todas las funciones a las que se debe llamar cuando ocurre un evento. Tiene un método fire()
que recorre esa lista y llama a todas las funciones a su vez. Probablemente también debería tener métodos para administrar la lista (eliminar una función de la lista que ya no es necesaria).
Los controladores o « suscriptores» son funciones a las que llamará cuando el evento realmente ocurra. El único problema es que necesitas controlar la firma de los controladores para que el evento pueda llamarlos sin hacer ninguna introspección adicional.
Aquí tienes un ejemplo ultra mínimo:
class Event(object):
def \_\_init\_\_(self, *args):
self.handlers = set()
self.args = args
def add(self, fn):
self.handlers.add(fn)
def remove(self, fn):
self.handlers.remove(fn)
def \_\_call\_\_(self, *args):
"""fire the event -- uses \_\_call\_\_ so we can just invoke the object directly..."""
runtime\_args = self.args + args
for each\_handler in self.handlers:
each\_handler(*runtime\_args)
class ExampleObject(object):
"""publish start and stop events"""
def \_\_init\_\_(self):
self.start = Event("started")
self.stop = Event("stopped")
def example\_handler(*args):
""" reacts to an event"""
print "example handler fired", args
fred = ExampleObject()
fred.start.add(example\_handler)
fred.stop.add(example\_handler)
fred.start()
fred.stop("optional extra arg")
Eso debería producir
example handler fired ("started",)
example handler fired ("stopped", "optional extra arg")
Los principales problemas de administración son:
Manejo de excepciones. debe decidir si el controlador debe ser seguro para excepciones o no. Si no, el código anterior está más o menos bien, pero si no quieres que un mal suscriptor elimine todo el programa, debes decidir cómo hacer frente a una excepción y si «anular la suscripción» del controlador infractor. .
Administración de memoria. El ejemplo solo usa una función como manejador; a menos que elimine () la función no tiene que administre su vida útil. Sin embargo, a menudo querrá tener objetos llamables o funciones miembro como controladores / suscriptores. Si es así, probablemente necesite usar referencias débiles en lugar del conjunto ingenuo utilizado en el ejemplo; de lo contrario, los controladores de eventos terminarán manteniendo vivos los objetos después de que deberían haber salido del alcance y deberían ser recolectados como basura.
Metadatos: El ejemplo incluye un poco de metadatos: la cadena que se pasa como Event()
s se declaran. Es posible que su aplicación necesite más o menos que esto. Más metadatos generalmente significa más acoplamiento, lo que no es ideal. Sin embargo, si todos sus controladores tienen la firma (*args, **kwargs)
, siempre puede pasar los datos y luego decidir en el nivel del controlador si le importa o no.
Buena referencia : El patrón del observador en Python
Ejemplo de la idea básica en acción: theodox / mGui
Respuesta
Si vas al sitio web del marco web tornado, tienen una página de ejemplos. En esa página hay un código de aplicación de chat de ejemplo. Es muy breve y comprensible.