2010-12-08 3 views
2

私はメッセージ・バスを持ち、そしてクラスは、たとえば、メッセージバスに多くの方法をサブスクライブ:クラスレベルでのデコレータの使用方法は?

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() 

それは動作しますが、私が欲しいものを、各メソッドのメッセージ・パスであるかを理解することは困難ですこの方法でメッセージバスを購読するデコレータを使用することです。この

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 

しかし、ここでは、解決するためにいくつかの困難されているように、それはすべての最初の、見えるでしょう、msg_bus属性が自己に、つまり、インスタンスに属します。クラスレベルでself.msg_busを取得できません。この問題を解決するために、私はこのようにそれを書き込むことができます。

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() 

私はBookingService.subscribationsにサブスクリプションを収集し、subscribe_allの後半msg_busするためにそれらを追加しようとするが、ここで問題が来ます。私はエラーが発生しました

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

サブスクリプションはサブスクリプション機能の範囲にないようですが、この問題を解決するにはどうすればよいですか?

+0

これを最もうまく行うには、メタクラス(またはおそらくスーパークラス)が必要です。 –

答えて

1

インスタンス上のリストに入れるのではなく、関数またはクラスのリストに入れます。

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() 

ただし、まだバインドされていないメソッドで問題が発生している可能性があります。 「自己」が何を意味するかに注意してください。

あなたはまた、

0

(現時点でself.subscribe()は、あなたが期待するどのように動作しませんが)クラス定義の外で「購読」、または「_subscribe」に名前を変更するか、self.subscribe()と呼ばれているに対処作りに移動することもできますクラス本体でサブスクリプションを定義すると、サブスクリプションがクラス属性になります。 ただし、使用するときは、グローバルとして使用します。メソッド から取得する必要がありますが、これはクラスが作成される前に行われるため、できません。

関数の属性として設定することも、関数と送り先の間のマッピングを持つグローバル辞書を設定することもできます。どちらの場合も、サブスクリプションがあるかどうかを調べるには、そのクラスのすべての関数をsubscribe_allメソッドで調べる必要があります。

関連する問題