2010-12-08 39 views
2

J'ai un bus de messages, et une classe abonnée de nombreuses méthodes pour le bus de messages, par exemple:Comment utiliser correctement un décorateur en classe?

class BookingService(object): 
    def start(self): 
     self.msg_bus.login(self.user, self.password) 
     self.msg_bus.subscribe('/broadcast/aliveResponse', self.handleAliveResponse) 
     self.msg_bus.subscribe('/broadcast/musicInfoUpdated', self.handleMusicInfo) 
     self.msg_bus.subscribe('/broadcast/radioOnline', self.handleRadioOnline) 
     self.msg_bus.subscribe('/broadcast/radioOffline', self.handleRadioOffline) 
     self.msg_bus.subscribe('/broadcast/online', self.handleBroadcastOnline) 
     self.msg_bus.subscribe('/proxy/aliveResponse', self.handleEvent) 
     self.msg_bus.subscribe('/proxy/online', self.handleProxyOnline) 
     self.msg_bus.subscribe('/proxy/radioReady', self.handleEvent) 
     self.msg_bus.subscribe('/proxy/radioUpdate', self.handleEvent) 
     self.msg_bus.subscribe('/proxy/radioClosed', self.handleEvent) 
     self.msg_bus.subscribe('/message_bus/detached', self.handleDetached) 
     self.msg_bus.run() 

Il fonctionne, mais il est difficile de comprendre ce qui est le chemin du message pour chaque méthode, ce que je veux est d'utiliser un décorateur pour vous abonner au bus de message avec méthode, il serait ressemble à ce

class BookingService(object): 

    @subscribe('/broadcast/aliveResponse') 
    @subscribe('/broadcast/onLine') 
    def handleEvent(self, dest, data): 
     print dest, data 

    @subscribe('/proxy/aliveResponse') 
    def handleAnotherEvent(self, dest, data): 
     print dest, data 

Mais voici quelques difficultés à résoudre, tout d'abord, l'attribut msg_bus appartient à l'instance, à savoir, à l'auto. Je ne peux pas obtenir le self.msg_bus au niveau de la classe. Pour résoudre ce problème, je peux l'écrire comme ceci:

class BookingService(object): 

    subscribations = [] 
    def subscribe(dest): 
     """Decorator for subscribing function to destination 

     """ 
     def callee(func): 
      subscribations.append((dest, func)) 
      return func 
     return callee 

    def subscribe_all(self): 
     for dest, func in self.subscribations: 
      self.msg_bus.subscribe(dest, func) 

    @subscribe('/broadcast/aliveResponse') 
    def handleEvent(self, dest, data): 
     print dest, data 

    def start(self): 
     self.subscribe_all() 

J'essaie de recueillir les souscriptions dans BookingService.subscribations et les ajouter à msg_bus plus tard dans subscribe_all, mais voilà le problème. Je suis une erreur

subscribations.append((dest, func)) 
NameError: global name 'subscribations' is not defined 

Il semble que les subscribations ne sont pas dans le cadre de la fonction abonnez-vous, comment résoudre ce problème?

+0

Pour ce faire, vous aurez besoin d'une métaclasse (ou éventuellement d'une super classe). –

Répondre

1

Plutôt que de le placer dans une liste sur l'instance, placez-le dans une liste sur la fonction ou la classe.

class BookingService(object): 

    def subscribe(dest): 
     """Decorator for subscribing function to destination 

     """ 
     def callee(func): 
      if not hasattr(func, 'subscriptions'): 
       func.subscriptions = [] 
      func.subscriptions.append((dest, func)) 
      return func 
     return callee 

    def subscribe_all(self): 
     for classmember in dir(self): 
      for dest, func in getattr(getattr(self, classmember), 'subscriptions', []): 
       self.msg_bus.subscribe(dest, func) 

    @subscribe('/broadcast/aliveResponse') 
    def handleEvent(self, dest, data): 
     print dest, data 

    def start(self): 
     self.subscribe_all() 

Vous pouvez toujours avoir des problèmes avec les méthodes n'étant pas liés, cependant; prends soin de ce que signifie "soi".

Vous pouvez également déplacer « subscribe » en dehors de la définition de la classe, ou le renommer « _subscribe » ou faire face à être appelé comme self.subscribe() (au moment self.subscribe() fonctionnera, mais pas comment vous attendre)

0

Vous définissez les abonnements dans le corps de la classe, ce qui en fait un attribut de classe. Cependant, lorsque vous l'utilisez, vous l'utilisez comme global. Vous devrez l'obtenir à partir de la méthode, mais puisque cela se produit avant que la classe a été créée, vous ne pouvez pas.

Vous pouvez le définir en tant qu'attribut sur la fonction, ou vous pouvez avoir un dictionnaire global avec un mappage entre les fonctions et les destinations. Dans les deux cas, vous devrez parcourir toutes les fonctions de la classe dans la méthode subscribe_all pour voir si elles ont des abonnements.