2014-04-12 1 views
4

저는 python-mpd2 모듈을 사용하여 GUI 애플리케이션에서 Raspberry Pi의 미디어 플레이어를 제어하고 있습니다. 따라서 백그라운드에서 연결 오류 및 시간 초과 (문제의 플레이어가 60 초 후에 MPD 연결을 삭제함)를 정상적으로 처리하고 싶습니다. 그러나 MPD 모듈에는 모든 명령을 보내거나 패치 할 수있는 정보가 검색되는 단일 입력 지점이 없습니다.Python에서 클래스 프록시하기

나는 mpd.MPDClient와 같은 모든 메소드에 액세스 할 수있는 클래스를 원하지만, 직접 오류 처리를 추가하겠습니다. 즉, 내가 할 경우 :

client.play() 

그리고 연결 오류가 발생했습니다. 나는 그것을 잡아서 같은 명령을 다시 보내고 싶습니다. 서버에 다시 연결해야하기 때문에 발생하는 작은 지연 이외에 사용자는 잘못된 점을 알아 채지 않아야합니다.

지금까지 여기에 나와있는 해결책이 있습니다. 내 응용 프로그램에서 작동하지만 내 목표를 실제로 수행하지는 않습니다.

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은 실제로 많이 있습니다. (하지만, 약간의 차이가 있습니다) 내가 이것을 쓰는되면서

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 비슷한 솔루션을 게시했다 나타났습니다 : 그래서 여기 자동적 인 해결책은 래퍼를 반환하는 사용자 정의 __getattr__의 사용을,이다 . 나는 왜 그/그가 그걸 삭제했는지 모르겠다. 그 대답이 삭제되지 않으면 기꺼이 그 대가를 치룰 것이다.

+0

사실,이 접근법은'command' 메서드가 호출 될 때 (OP가 원하는) 오류 처리를 수행 할 수 없기 때문에 제 대답을 삭제했습니다. 오류 처리를 가능하게 만드는 것은 좀 더 복잡해 지지만 또 다른 대답이 올 것입니다. – MatToufoutu

+0

@MatToufoutu는 어떤 종류의 오류 처리가 누락 되었는가를 명확히하지 않습니다 ... – shx2

+1

내 잘못은 잘못되었습니다 (토요일, ^^) 그래도 대답은 좀 더 영리하다. (타입 검사와 인수 처리), 내가 삭제 한 채로 남겨 두겠다.) – MatToufoutu

관련 문제