Как правильно использовать декоратор на уровне класса? - PullRequest
2 голосов
/ 08 декабря 2010

У меня есть шина сообщений, и класс подписывает много методов на шину сообщений, например:

class BookingService(object):
    def start(self):
        self.msg_bus.login(self.user, self.password)
        self.msg_bus.subscribe('/broadcast/aliveResponse', self.handleAliveResponse)
        self.msg_bus.subscribe('/broadcast/musicInfoUpdated', self.handleMusicInfo)
        self.msg_bus.subscribe('/broadcast/radioOnline', self.handleRadioOnline)
        self.msg_bus.subscribe('/broadcast/radioOffline', self.handleRadioOffline)
        self.msg_bus.subscribe('/broadcast/online', self.handleBroadcastOnline)
        self.msg_bus.subscribe('/proxy/aliveResponse', self.handleEvent)
        self.msg_bus.subscribe('/proxy/online', self.handleProxyOnline)
        self.msg_bus.subscribe('/proxy/radioReady', self.handleEvent)
        self.msg_bus.subscribe('/proxy/radioUpdate', self.handleEvent)
        self.msg_bus.subscribe('/proxy/radioClosed', self.handleEvent)
        self.msg_bus.subscribe('/message_bus/detached', self.handleDetached)
        self.msg_bus.run()

Это работает, но трудно понять, каков путь сообщения для каждого метода,я хочу использовать декоратор для подписки на шину сообщений методом, это выглядело бы так:

class BookingService(object):

    @subscribe('/broadcast/aliveResponse')
    @subscribe('/broadcast/onLine')
    def handleEvent(self, dest, data):
        print dest, data

    @subscribe('/proxy/aliveResponse')
    def handleAnotherEvent(self, dest, data):
        print dest, data

Но вот некоторые трудности, которые необходимо решить, прежде всего, атрибут msg_bus принадлежит экземпляру,а именно, к себе.Я не могу получить self.msg_bus на уровне класса.Чтобы решить эту проблему, я могу написать это так:

class BookingService(object):

    subscribations = []
    def subscribe(dest):
        """Decorator for subscribing function to destination

        """
        def callee(func):
            subscribations.append((dest, func))
            return func
        return callee

    def subscribe_all(self):
        for dest, func in self.subscribations:
            self.msg_bus.subscribe(dest, func)

    @subscribe('/broadcast/aliveResponse')
    def handleEvent(self, dest, data):
        print dest, data

    def start(self):
        self.subscribe_all()

Я пытаюсь собрать подписки в BookingService.subscribeations и добавить их в msg_bus позже в subscribe_all, но здесь возникает проблема.Я получил ошибку

subscribations.append((dest, func))
NameError: global name 'subscribations' is not defined

Кажется, что подписка не входит в сферу функции подписки, как решить эту проблему?

Ответы [ 2 ]

1 голос
/ 08 декабря 2010

Вместо того, чтобы помещать его в список экземпляра, поместите его в список функции или класса.

class BookingService(object):

    def subscribe(dest):
        """Decorator for subscribing function to destination

        """
        def callee(func):
            if not hasattr(func, 'subscriptions'):
                func.subscriptions = []
            func.subscriptions.append((dest, func))
            return func
        return callee

    def subscribe_all(self):
        for classmember in dir(self):
            for dest, func in getattr(getattr(self, classmember), 'subscriptions', []):
                self.msg_bus.subscribe(dest, func)

    @subscribe('/broadcast/aliveResponse')
    def handleEvent(self, dest, data):
        print dest, data

    def start(self):
        self.subscribe_all()

Однако у вас могут возникнуть проблемы с методами, которые не связаны; позаботься о том, что значит «я».

Вы также можете переместить «подписку» за пределы определения класса, или переименовать его в «_subscribe» или сделать так, чтобы он назывался self.subscribe() (на данный момент self.subscribe() будет работать, но не так, как вы ожидаете)

0 голосов
/ 08 декабря 2010

Вы определяете подписки в теле класса, что делает его атрибутом класса. Однако когда вы используете его, вы используете его как глобальный. Вы должны были бы получить это от метода, но так как это происходит до того, как класс был создан, вы не можете.

Вы можете установить его как атрибут функции или иметь глобальный словарь с отображением между функциями и назначениями. В обоих случаях вам придется пройти через все функции в классе в методе subscribe_all, чтобы увидеть, есть ли у них подписки.

...