Usando un cliente websocket como una clase en Python

Estoy intentando acceder a algunos datos utilizando websockets, pero realmente no puedo sortear los ejemplos dados en la documentación de websockets.

Tengo este código ( https://pypi.org/project/websocket_client/ ) y quiero transformarlo en una Clase

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

La idea es tener toda esta funcionalidad de websocket en una clase para que yo pueda crear un objeto de esa clase.

Traté de empezar a hacerlo, pero ni siquiera puedo pasar esto:

 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) 

El error comienza de inmediato en on_message diciendo que es una “referencia no resuelta”.

Empaquete la llamada dentro de una función lambda anónima para lograr una llamada adecuada con el self correcto:

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

WebSocketApp necesita objetos que se puedan llamar para sus devoluciones de llamada (tanto los que pasa en el constructor, como on_message , y el que está configurando después del hecho, on_open ).

Las funciones simples son objetos que se pueden llamar, por lo que su versión que no es OO funciona bien, porque está pasando las funciones simples.

Los métodos encuadernados también son objetos que se pueden llamar. Pero tu versión OO no está pasando los métodos enlazados. Un método enlazado es, como su nombre lo indica, enlazado a un objeto. Haces esto usando la notación obj.method . En tu caso, eso es 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 

Sin embargo, tienes otro problema. Si bien esto hará que su error desaparezca, no hará que su código realmente funcione. Un método normal tiene que tomarse como primer argumento:

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

También vale la pena señalar que realmente no estás usando la clase para nada. Si nunca accede a nada por self , la clase solo actúa como un espacio de nombres. No es que esto siempre sea algo malo, pero generalmente es una señal de que necesita al menos pensar en su diseño. ¿Hay realmente algún estado que debas mantener? Si no, ¿por qué quieres una clase en primer lugar?

Es posible que desee volver a leer la sección de tutoriales sobre Clases para comprender los métodos, el self , etc.

Necesitas agregar “self” a tus métodos de clase:

 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) 

El Sí mismo hace que esos métodos sean métodos de Clase. Conseguí que este que funcionara como la firma de los métodos on_error / message / close se satisfaga si se llama por sí mismo y se referirá a la clase en sí.

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

Me gustaría intentar de esta manera:

 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 

El uso de la función interna en el método __init__(self) podría evitar el problema que el número de argumentos de on_message(self, ws, message) no coincide con el número de WebSocketApp proporciona su argumento on_message (el método class tiene un argumento más self ).

Tengo un handler arriba para manejar el mensaje, método close(self) para limpiar algunos recursos si tengo, run_forever(self) para ejecutar websocket.

Esto está funcionando:

 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) 

Pero no tienes acceso a ti mismo.