python - 如何在类级别正确使用装饰器?

标签 python class decorator

我有一个消息总线,一个类订阅了消息总线的很多方法,例如:

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属性是属于instance的,也就是属于self的。我无法在类里面获得 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.subscribations 中,稍后在 subscribe_all 中将它们添加到 msg_bus,但问题来了。我遇到了一个错误

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

subscribes好像不在subscribe函数的范围内,请问如何解决?

最佳答案

与其将其放入实例的列表中,不如将其放入函数或类的列表中。

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

然而,您可能仍然遇到未绑定(bind)方法的问题;注意“ self ”的含义。

您可能还想将“subscribe”移到类定义之外,或将其重命名为“_subscribe”,或使其适应被调用为 self.subscribe()(此时 self.subscribe() 会起作用,但不是你期望的那样)

关于python - 如何在类级别正确使用装饰器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4383702/

相关文章:

python - 在python中获取装饰函数的参数

java - 为什么在装饰器中调用安全认证属性 `principal.displayName`会抛出异常?

python - 在 Windows 7 中安装 talib 失败

javascript - 如何在 jQuery 中一次设置多个类号?

c++ - 无法在同一文件中定义 2 个不同类的构造函数

class - 是否建议在 UML 类图中与枚举类建立关联?

python - Teradata 和 sqlachemy 连接

python 将 OpenDap 加载到 NetcdfFile

python - 使用正则表达式在字符串中查找两个相同的字符

php - php 中的 python 装饰器等效项