开发者

How to use a decorator in class level correctly?

I have a message bus, and a class subscribes many methods to the message bus, for example:

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('/b开发者_如何学编程roadcast/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()

It works, but it is difficult to understand what is the message path for each method, what I want is to use a decorator to subscribe to the message bus with method, it would looks like this

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

But here are some difficulty to solve, first of all, the msg_bus attribute belongs to instance, namely, to self. I can't get the self.msg_bus in class level. To solve this problem, I can write it like this:

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()

I try to collect subscriptions into BookingService.subscribations and add them to msg_bus later in subscribe_all, but here comes the problem. I got an error

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

It seems that the subscribations is not in the scope of subscribe function, how to solve this problem?


Rather than putting it into a list on the instance, put it into a list on the function or class.

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()

You may still have issues with methods not being bound, however; take care with what "self" means.

You may also want to move "subscribe" outside the class definition, or rename it "_subscribe" or make it cope with being called as self.subscribe() (at the moment self.subscribe() will work but not how you expect)


You define subscribations in the class body, which makes it a class attribute. However, when you use it, you use it as a global. You would have to get it from the method, but since this happens before the class has been created, you can't.

You can set it as an attribute on the function, or you can have a global dictionary with a mapping between functions and destinations. In both cases you will have to go through all functions in the class in the subscribe_all method to see if they have subscriptions.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜