【问题标题】:Using a websocket client as a class in python在 python 中使用 websocket 客户端作为类
【发布时间】:2015-01-14 20:28:54
【问题描述】:

我正在尝试使用 websockets 访问一些数据,但我无法真正绕过 websockets 文档中给出的示例。

我有这段代码 (https://pypi.org/project/websocket_client/),想把它转换成一个类。

import websocket
import thread
import time

def on_message(ws, message):
    print message

def on_error(ws, error):
    print error

def on_close(ws):
    print "### closed ###"

def on_open(ws):
    def run(*args):
        for i in range(3):
            time.sleep(1)
            ws.send("Hello %d" % i)
        time.sleep(1)
        ws.close()
        print "thread terminating..."
    thread.start_new_thread(run, ())


if __name__ == "__main__":
    websocket.enableTrace(True)
    ws = websocket.WebSocketApp("ws://echo.websocket.org/",
                                on_message = on_message,
                                on_error = on_error,
                                on_close = on_close)
    ws.on_open = on_open

    ws.run_forever()

我们的想法是在一个类中拥有所有 websocket 功能,这样我就可以创建该类的一个对象。

我试着开始做,但我什至无法通过这个:

class MySocket(object):
    def __init__(self):
        websocket.enableTrace(True)
        self.ws = websocket.WebSocketApp("ws://echo.websocket.org:12300/foo",
                                    on_message = on_message,
                                    on_error = on_error,
                                    on_close = on_close)

    def on_message(ws, message):
        print message

    def on_error(ws, error):
        print error

    def on_close(ws):
        print "### closed ###"

    def on_open(ws):
    ws.send("Hello %d" % i)

错误在on_message 中立即开始,说这是一个“未解决的引用”。

【问题讨论】:

    标签: python class websocket


    【解决方案1】:

    您需要在类方法中添加“self”:

    class MySocket(object):
        def __init__(self):
            websocket.enableTrace(True)
            self.ws = websocket.WebSocketApp("ws://echo.websocket.org:12300/foo",
                                    on_message = self.on_message,
                                    on_error = self.on_error,
                                    on_close = self.on_close)
    
        def on_message(self, ws, message):
            print message
    
        def on_error(self, ws, error):
            print error
    
        def on_close(self, ws):
            print "### closed ###"
    
        def on_open(self, ws):
            ws.send("Hello %d" % i)
    

    【讨论】:

    • 我不是那样工作的。我尝试: ws = MySocket(); ws.run_forever();我得到错误:“MySocket”对象没有属性“run_forever”。
    • ws 不是 WebSocketApp 对象。它是一个 MySocket 对象。您需要在对象中添加代码以启动它,或者只需在属性上调用 run_foreever,例如:ws.ws.run_forever()
    • 谢谢。我想我只是不理解这背后的原则。我现在将停止使用这些类,只使用普通函数。
    【解决方案2】:

    WebSocketApp 的回调需要可调用对象(您在构造函数中传递的对象,如 on_message,以及事后设置的对象,on_open)。

    普通函数是可调用对象,因此您的非 OO 版本可以正常工作,因为您传递的是普通函数。

    绑定方法是也是可调用对象。但是您的 OO 版本没有传递绑定方法。顾名思义,绑定方法是绑定到对象的。您可以使用obj.method 表示法来做到这一点。在你的情况下,那是self.on_message:

    self.ws = websocket.WebSocketApp("ws://echo.websocket.org/",
                                     on_message = self.on_message,
                                     on_error = self.on_error,
                                     on_close = self.on_close)
    self.ws.on_open = self.on_open
    

    但是,您还有另一个问题。虽然这会让你的错误消失,但它不会让你的代码真正工作。普通方法必须将self 作为其第一个参数:

    def on_message(self, ws, message):
        print message
    

    同样值得注意的是,您并没有真正使用这个类来做任何事情。如果您从不访问self 之外的任何内容,则该类就像一个命名空间。并不是说这总是一件坏事,但这通常表明您至少需要仔细考虑您的设计。真的有需要维护的状态吗?如果没有,你为什么要一开始就上课?

    您可能需要重新阅读tutorial section on Classes 以了解方法、self 等。

    【讨论】:

    • 好吧,我不能让它像那样工作。我尝试: ws = MySocket(); ws.run_forever();我得到错误:'MySocket' 对象没有属性'run_forever'。但也许你是对的,我应该把它放在课堂上。
    • @jbssm:好吧,您定义了一个没有run_forever() 方法的类MySocket。您创建该类的一个实例并尝试在其上调用run_forever()。你期望会发生什么?如果您希望您的班级自动将所有未知方法委托给self.ws,您可以这样做,但您需要为此编写代码。
    • 谢谢。我将停止使用该类并尝试使用正常功能。
    【解决方案3】:

    Self 将这些方法作为类方法,让这个作为 on_error/message/close 方法签名将得到满足,如果由 self 调用,它将引用类本身。

     class MySocket(object):
       def __init__(self,x):
         websocket.enableTrace(True)
         ## Only Keep the object Initialisation here  
         self.x=x
         self.ws=None
    
         # call This method from a Object and it will create and run the websocket 
        def ws_comm(self):
            self.ws = websocket.WebSocketApp(self.WS_URL,on_message = 
            self.on_message,on_error =self.on_error,on_close = self.on_close)
            self.ws.on_open = self.on_open
            self.ws.run_forever()
    
        def on_error(self,ws, error):
            print "onError", error
    
        def on_close(self,ws):
           print "onClosed"
    
        #Send some message on open 
        def on_open(self,ws):
           self.ws.send(json.dumps(register_msg))
    
        def on_message(self,ws, msg):
           self.ws.send(json.dumps(msg))
    
    
     user1=Userapp('x')
     user1.ws_comm()
    

    【讨论】:

      【解决方案4】:

      我想试试这个方法:

      class FooClient(object):
          def __init__(self):
              def on_message(ws, message):
                  print message
                  # use 'self' variable to access other resource
                  # handle message from websocket server like this
                  self.handler.handle(message)
      
              def on_error(ws, error):
                  print error
      
              def on_close(ws):
                  print "### closed ###"
      
              def on_open(ws):
                  ws.send("Hello %d" % i)
      
              # assign to 'self.handler'
              self.handler = FooHandler()
              # maybe there are another module should be initiated
              # ...
      
              websocket.enableTrace(True)
              self.ws = websocket.WebSocketApp("ws://echo.websocket.org:12300/foo",
                                               on_message = on_message,
                                               on_error = on_error,
                                               on_close = on_close)
      
          def run_forever(self):
              self.ws.run_forever()
      
          def close(self):
              """clean other resources"""
              pass
      

      在方法__init__(self)中使用内部函数可以避免on_message(self, ws, message)方法的参数数量与WebSocketApp提供给它的参数on_message的数量不匹配的问题(类方法多了一个参数self )。

      我上面有一个handler 来处理消息,如果我有方法close(self) 来清理一些资源,run_forever(self) 来运行websocket。

      【讨论】:

      • 请描述您提供的解决方案
      • @DineshGhule 我添加了一些描述,如果有问题请评论。
      【解决方案5】:

      这是有效的:

      class MySocket(object):
          def __init__(self):
              websocket.enableTrace(True)
              self.ws = websocket.WebSocketApp("ws://echo.websocket.org:12300/foo",
                                      on_message = self.on_message,
                                      on_error = self.on_error,
                                      on_close = self.on_close)
      
          @staticmethod
          def on_message(ws, message):
              print message
      
          @staticmethod
          def on_error(ws, error):
              print error
      
          @staticmethod
          def on_close(ws):
              print "### closed ###"
      
          @staticmethod
          def on_open(ws):
              ws.send("Hello %d" % i)
      

      但你无权访问自己

      【讨论】:

        【解决方案6】:

        将调用封装在匿名lambda 函数中,以使用正确的self 实现正确调用:

        class Client:
            def __init__(self, db, symbols):
                self.ws = websocket.WebSocketApp("wss://the.server.com/api",
                            on_message = lambda ws,msg: self.on_message(ws, msg),
                            on_error   = lambda ws,msg: self.on_error(ws, msg),
                            on_close   = lambda ws:     self.on_close(ws),
                            on_open    = lambda ws:     self.on_open(ws))
        
            def on_message(self, ws, message):
                    msg = json.loads(message)
                    print(msg)
            ...
        

        【讨论】:

        • 这似乎是解决问题的正确方法
        • 没有 lambda 会更简单:on_message=self.on_message, on_error=self.on_error, ...
        • @gil9red 没有 lambda,你将失去 self。也就是说,在on_message里面,self不会指向你对象的实例。
        • 非常感谢。节省我的时间。
        • 我已经尝试过 lambda 和 self.on_message 但我仍然得到on_open() missing 1 required positional argument: 'ws'
        【解决方案7】:
        import websocket
        
        try:
            import thread
        except ImportError:
            import _thread as thread
        import time
        
        
        class OnyxGenericClient:
            """
            Onyx Client Interface
        
            """
        
            def __init__(self, ):
                websocket.enableTrace(True)
                ws = websocket.WebSocketApp("ws://localhost:3000/",
                                                 on_message=self.on_message,
                                                 on_error=self.on_error,
                                                 on_close=self.on_close)
                self.ws = ws
                self.ws.on_open = self.on_open
                self.ws.run_forever()
        
            # def initiate(self):
        
            def on_message(self, message):
                print(message)
                return message
        
            def on_error(self, error):
                return error
        
            def on_close(self):
                print("### closed ###")
        
            def run(self, *args):
                global driver
                driver = True
                while driver:
                    try:
                        time.sleep(1)
                        print("Say something nice")
                        p = input()
                        self.ws.send(p)
                    except KeyboardInterrupt:
                        driver = False
                time.sleep(1)
                self.ws.close()
                print("thread terminating...")
        
            def on_open(self):
                thread.start_new_thread(self.run, ())
        
        
        if __name__ == "__main__":
            websocket.enableTrace(True)
            onyx_client = OnyxGenericClient()
        

        不知道为什么大家还在放ws这个参数。

        阅读错误日志。

        文件“venv/lib/python3.7/site-packages/websocket/_app.py”,第 343 行,在 _callback 回调(*args)

            def _callback(self, callback, *args):
            if callback:
                try:
                    if inspect.ismethod(callback):
                        callback(*args)
                    else:
                        callback(self, *args)
        
                except Exception as e:
                    _logging.error("error from callback {}: {}".format(callback, e))
                    if _logging.isEnabledForDebug():
                        _, _, tb = sys.exc_info()
                        traceback.print_tb(tb)
        

        看看我们的回调,on_open(self, ws)

        try 块执行时,它会检查我们的回调是一个方法还是一个函数。 如果它是一个方法,它将执行 callback(*args) 已经来自我们的 CustomClient 的 self 已经作为 (*args) 中的参数传递。请注意,它已经在def _callback(self, callback, *args) 中拥有自己的self。 因此,作为 CustomClient 实例的每个回调都不应该有 ws 参数。

        【讨论】:

        • 谢谢@vc74。我什至不记得我什么时候回答的。不过很有道理。
        【解决方案8】:

        仅更新此页面上其他作者编写的代码,这对我有用。 问题是在 on_message 这样的事件回调函数定义中,我们不应该使用 ws 作为参数。 self 负责处理它,在这些事件处理函数的主体中,我们应该使用 self.ws

        class MySocket(object):
            def __init__(self):
                websocket.enableTrace(True)
                self.ws = websocket.WebSocketApp("ws://echo.websocket.org:12300/foo",
                                        on_message = self.on_message,
                                        on_error = self.on_error,
                                        on_close = self.on_close)
        
            
            def on_message(self, message):
                # if you want to send something use like this
                # self.ws.send()
                print message
        
            def on_error(self, error):
                print error
        
            def on_close(self):
                print "### closed ###"
        
            def on_open(self):
                self.ws.send("Hello Message")
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-02-05
          • 2011-12-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-03
          • 2015-07-04
          相关资源
          最近更新 更多