سؤال

أنا أستخدم وحدة python-mpd2 للتحكم في مشغل الوسائط على Raspberry Pi في تطبيق واجهة المستخدم الرسومية.وبالتالي، أرغب في التعامل مع أخطاء الاتصال والمهلات بأمان (يقوم اللاعب المعني بإسقاط اتصالات 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 هو في الواقع الكثير.لذا، إليك الحل السحري التلقائي، باستخدام التخصيص __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 قد نشر حلاً مشابهًا (على الرغم من وجود بعض الاختلافات).لا أعلم لماذا قام بحذفها..إذا تم إلغاء حذف هذه الإجابة، فسأمنحها بكل سرور الفضل الذي تستحقه.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top