Прокси в классе в Python
-
21-12-2019 - |
Вопрос
Я использую модуль Python-MPD2 для управления медиаплеером на Raspberry Pi в приложении GUI. Таким образом, я хотел бы изящно обрабатывать ошибки подключения и тайм-аута (игрок в вопросе падает MPD соединения через 60 секунд) на заднем плане. Тем не менее, модуль MPD не имеет единой точки записи, через который все команды отправляются или информация извлекается, что я могу исправить.
Я хотел бы, чтобы класс, который позволяет доступу ко всем то же методам, что и 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")
.
Но это кажется далеко от лучшего способа достичь его.
Решение
Если вы не возражаете против создания списка всех 91 строк, формирующихся Имена команд , вы можете сделать что-то вдоль линий Этот ответ .Я считаю, что этот подход имеет много преимуществ, потому что это связано с меньшей волшебной.
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 разместил подобное решение (хотя есть некоторые различия).Я не знаю, почему он / он удалил его ... Если этот ответ становится восстановленным, я бы с удовольствием дал ему кредит, это заслуживает.