как сделать функцию декоратора частью класса - PullRequest
1 голос
/ 14 мая 2019

Я хочу, чтобы функции были частью класса, который я создаю, но я получаю сообщение об ошибке Возможно, проблема в том, что функция декоратора будет функцией в отделе.Есть ли решение проблемы?Спасибо.

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 Ответ

3 голосов
/ 14 мая 2019

Вы не можете использовать декоратор в методе, где выражение декоратора ссылается на атрибут экземпляра.Это потому, что декораторы выполняются , когда создается функция, которую они декорируют .Внутри тела оператора 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() метод принимает обработчик в качестве второго аргумента, но вы также можете использовать 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() метод блокирует, он не возвращаетДо тех пор, пока соединение не закончилось.Обычно вы не помещаете такой вызов в метод __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()
...