如何使装饰器函数成为类的一部分

时间:2019-05-14 10:12:44

标签: python class decorator

我希望函数成为我正在构建的类的一部分,但出现错误可能是装饰器函数将成为部门中的函数。有解决问题的办法吗?谢谢。

import engineio

class Websocket:

    def __init__(self):
        self.eio = engineio.Client()
        self.eio.connect('http://localhost:5000')
        self.eio.wait()

    # get error in this function       
    @eio.on('connect')
    def on_connect():
        print('connection established')

1 个答案:

答案 0 :(得分:3)

您不能在装饰器表达式引用实例属性的方法上使用装饰器。这是因为装饰器是在装饰函数创建时执行的。在class语句主体内部,这意味着当应用装饰器时,还没有类,而且没有类,也将没有任何实例。

您有两个选择:

  • 只需在类self.eio.on('connect')中调用__init__,并传入绑定方法即可:

    class Websocket:
    
        def __init__(self):
            self.eio = engineio.Client()
            self.eio.connect('http://localhost:5000')
            self.eio.on('connect', self.on_connect)
            # don't call wait, see below
    
        def on_connect(self):
            print('connection established')
    

    之所以可行,是因为在调用__init__时,您已经拥有一个类和该类的实例(由self引用),并且self.on_connect返回对绑定方法的引用(调用它将传入self)。 @....装饰器语法只是语法糖,您没有拥有来使用它。 engineio.Client.on() method接受处理程序作为第二个参数,但是您也可以使用self.eio.on('connect')(self.on_connect),它是修饰符语法所做的字面翻译。

  • __init__中使用嵌套函数,并进行装饰:

    class Websocket:
    
        def __init__(self):
            self.eio = engineio.Client()
            self.eio.connect('http://localhost:5000')
    
            @self.eio.on('connect')
            def on_connect():
                print('connection established')
    
            # don't call wait, see below
    
    
    but that makes it much harder to use that function directly from other code. 
    

请注意,engineio.Client.wait() method会阻塞,直到连接结束才返回。通常,您不会将此类调用放在类的__init__方法中!

使用一个类来处理engineio事件是很棒的,但是不要从该类开始客户端连接。我会这样做:

class Websocket:
    def __init__(self, socket_url):
        self.eio = engineio.Client()
        self.eio.connect(socket_url)
        self.eio.on('connect', self.on_connect)
        # other registrations

    def on_connect(self):
        # handle connection

    # other handlers

    def wait(self):
        self.eio.wait()

websocket = Websocket('http://localhost:5000)
websocket.wait()