在Python中代理类
-
21-12-2019 - |
题
我正在使用python-mpd2模块在GUI应用程序中控制Raspberry Pi上的媒体播放器。因此,我想在后台优雅地处理连接错误和超时(有问题的播放器在60秒后丢弃MPD连接)。但是,MPD模块没有单个入口点,通过该入口发送所有命令或检索我可以修补的信息。
我想要一个类,它允许访问所有与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")
但这似乎远非实现它的最佳方式。
解决方案
如果您不介意创建所有91个字符串的列表。 命令名称, ,你可以沿着 这个答案.我相信这种方法有很多优点,因为它涉及的魔法较少。
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发布了一个类似的解决方案(尽管有一些差异)。不知道为什么s/他删除了它。..如果这个答案没有被删除,我很乐意给予它应有的荣誉。
不隶属于 StackOverflow