2012-05-04 6 views
5

Estoy creando un marco de distribución de eventos que descodifica mensajes y vuelve a llamar al código de usuario. Mi C++ fondo sugiere que escribo:¿Es idiomático Python usar una clase abstracta para callbacks de controladores de eventos?

class Handler: 
    def onFoo(self): 
     pass 
    def onBar(self): 
     pass 

class Dispatcher: 
    def __init__(self): 
     self.handler = Handler() 

    def run(): 
     while True: 
      msg = decode_message() # magic 
      if msg == 'foo': 
       handler.onFoo() 
      if msg == 'bar': 
       handler.onBar() 

continuación, el usuario marco podría escribir algo como:

class MyHandler(Handler): 
    def onFoo(self): 
     do_something() 

dispatcher = Dispatcher() 
myHandler = MyHandler() 
dispatcher.handler = myHandler 
dispatcher.run() 

Pero también se puede imaginar poniendo onFoo() y onBar() como métodos de Dispatcher y dejar que el usuario reemplazarlos con otros métodos. A continuación, el código de usuario se vería así:

def onFoo(): 
    do_something() 

dispatcher = Dispatcher() 
dispatcher.onFoo = onFoo 

yo también podría hacer una lista de Dispatcher.onFoo callables, por lo que el usuario puede adjuntar más de un manejador como en C#.

¿Cuál es la forma más pitonica de hacerlo?

+0

¿Por qué está creando un marco de despachador de eventos? Ya existen muchos. – Marcin

+0

No estoy construyendo nada de propósito general: probablemente hice que el proyecto parezca más grande de lo que realmente es. Es solo una capa de mensajería que decodifica los mensajes de Buffers de Protocolo y llama a las funciones apropiadas. – japreiss

+0

Para expandir un poco más: quiero evitar depender demasiado de las bibliotecas de terceros, ya que he encontrado algunos problemas para integrarlos en la gran base de código propietario de mi empresa. Quiero mantener la posibilidad de arrancar las bibliotecas y reemplazarlas con el código de Invented Here. – japreiss

Respuesta

4

Yo no diría que no hay nada particularmente mal de hacerlo la primera forma, especialmente si desea permitir Dispatcher objetos para personalizar de una manera organizada en tiempo de ejecución (es decir, al pasar diferentes tipos de Handler objetos a ellos), si su Handler s necesita interactuar y mantener un estado complejo.

Pero realmente no ganas nada al definir una clase base Handler de esta manera; una clase todavía podría subclase Handler sin anular ningún método, porque esta no es una clase base abstracta, es solo una clase base regular. Entonces, si hay algunos comportamientos predeterminados razonables, sugeriría que se construyan en Handler. De lo contrario, sus usuarios no obtendrán nada de Handler en absoluto; también podrían definir su propia clase Handler. Aunque si solo quieres proporcionar un marcador de posición no operativo, entonces esta configuración está bien.

En cualquier caso, yo personalmente preferiría el primer acercamiento al segundo que sugiera; No estoy seguro de que ninguno de los dos sea más "pitónico", pero el primero me parece más limpio, ya que mantiene separadas las lógicas Handler y Dispatcher. (Evita situaciones como la que se ve en threading.Thread donde sólo se puede anular de manera segura algunos métodos -. Siempre he encontrado que un poco chocante)

me siento Debo señalar, sin embargo, que si realmente quiero una clase base abstracta de buena fe, ¡deberías escribir una! A partir de 2.6, Python proporciona soporte para el abstract base classes flexible con muchas funciones agradables. Por ejemplo, puede definir un método abstracto con el decorador abstractmethod, que garantiza que debe ser anulado por la subclase; pero también puedes definir métodos regulares que no deben ser anulados. Si está buscando una versión Pythonic del lenguaje C++, esta es probablemente la mejor manera de hacerlo; no es lo mismo, por supuesto, pero se acerca más de lo que tiene ahora.

+0

No me importan tanto las clases base abstractas. Quiero proporcionar un comportamiento predeterminado no operativo para que los usuarios no tengan que manejar todos los eventos si no lo desean. – japreiss

+0

@japreiss, ah, ya veo, eso tiene sentido. No estaba pensando en eso de esa manera. No estoy seguro de que _pythonicity_ entra en juego entonces; por lo que vale, preferiría la primera versión, pero no veo que tampoco sea más pitónico que la otra. – senderle

+0

¿Hay una mejor manera de hacerlo? Parece que Twisted usa la herencia de clases para los controladores de eventos. No he hecho muchas cosas impulsadas por eventos en Python, así que no estoy seguro de si esta es la manera 'normal'. – japreiss

Cuestiones relacionadas