2014-04-12 20 views
4

我正在使用python-mpd2模塊在GUI應用程序中控制Raspberry Pi上的媒體播放器。因此,我想在後臺優雅地處理連接錯誤和超時(玩家在60秒後放棄MPD連接)。但是,MPD模塊沒有單個輸入點,通過它可以發送所有命令或檢索可以修補的信息。在Python中代理一個類

我想要一個允許訪問所有mpd.MPDClient相同方法的類,但讓我添加自己的錯誤處理。換句話說,如果我這樣做:

client.play() 

並引發connectione錯誤,我想趕上它,並重新發送相同的命令。除了必須重新連接到服務器造成的小延遲之外,用戶不應該注意到任何錯誤。

到目前爲止,這裏是我提出的解決方案。它在我的應用程序中工作,但並未真正實現我的目標。

from functools import partial 
from mpd import MPDClient, ConnectionError 

class PersistentMPDClient(object): 
    def __init__(self, host, port): 
     self.host = host 
     self.port = port 
     self.client = MPDClient() 
     self.client.connect(self.host, self.port) 

    def command(self, cmd, *args, **kwargs): 
     command_callable = partial(self.client.__getattribute__(cmd), *args, **kwargs) 
     try: 
      return command_callable() 
     except ConnectionError: 
      # Mopidy drops our connection after a while, so reconnect to send the command 
      self.client._soc = None 
      self.client.connect(self.host, self.port) 
      return command_callable() 

我的方法添加到這個類的每一個MPD命令,例如:

def play(self): 
    return self.command("play") 

但這似乎遠遠沒有最好的方式來完成它。

+0

需要處理多少個*命令? – shx2

+0

有91個命令。並非所有這些都是必要的或將用於我的應用程序,但其中很大一部分是。 –

+0

如果您不介意創建所有91個字符串形成*命令名稱*的列表,您可以按照[此答案](http://stackoverflow.com/a/534597/2096752)的方式進行操作。我相信這種方法具有許多優點,因爲它涉及的魔法較少。 OTOH,91確實很多,所以更基本的基於__getattr__的解決方案可能更合適。 – shx2

回答

4

如果您不介意創建所有91個字符串的列表,形成命令名稱,則可以按照this answer的順序進行操作。我相信這種方法具有許多優點,因爲它涉及的魔法較少。

OTOH 91確實很多。因此,這裏是一個自動魔法的解決方案,使得定製__getattr__,它返回一個包裝的使用:

from functools import partial 
import types 

class DummyClient(object): 
    def connect(self, *a, **kw): print 'connecting %r %r' % (a, kw) 
    def play(self): print 'playing' 
    def stop(self): print 'stopping' 

class PersistentMPDClient(object): 
    def __init__(self, host, port): 
     self.host = host 
     self.port = port 
     self.client = DummyClient() 
     self.client.connect(self.host, self.port) 

    def __getattr__(self, attr, *args): 
     cmd = getattr(self.client, attr, *args) 
     if isinstance(cmd, types.MethodType): 
      # a method -- wrap 
      return lambda *a, **kw: self.command(attr, *a, **kw) 
     else: 
      # anything else -- return unchanged 
      return cmd 

    def command(self, cmd, *args, **kwargs): 
     command_callable = partial(self.client.__getattribute__(cmd), *args, **kwargs) 
     try: 
      return command_callable() 
     except ConnectionError: 
      # Mopidy drops our connection after a while, so reconnect to send the command 
      self.client._soc = None 
      self.client.connect(self.host, self.port) 
      return command_callable() 

c = PersistentMPDClient(hostname, port) 
c.play() 
c.stop() 

當我寫這件事,我注意到@MatToufoutu已經發布了類似的解決方案(有一定的差異,雖然) 。我不知道他/她爲什麼刪除它......如果這個答案沒有被刪除,我很樂意給它應有的信譽。

+0

事實上,我刪除了我的答案,因爲這種方法不允許在調用'command'方法時執行錯誤處理(OP希望)。使錯誤處理可能使事情變得更復雜,但另一個答案是:) – MatToufoutu

+0

@MatToufoutu不清楚我錯過了什麼樣的錯誤處理... – shx2

+1

我的不好,得到的東西錯了(星期六,你知道^^) ,但是,你的回答更聰明,我之前發佈的內容(類型檢查和參數處理),我將它刪除;) – MatToufoutu