【问题标题】:Two-Way communication between classes python (edited + code added)python类之间的双向通信(编辑+代码添加)
【发布时间】:2017-04-19 15:09:15
【问题描述】:

所以,我有需要相互交流的类。例如,我构建了聊天程序的客户端。一个类处理套接字,另一个类处理 GUI。所以 GUI 类必须从 sockets 类中获取接收到的数据,此外还必须通过 socket 类发送消息。

问题是,如果你让一个类包含另一个类,你就不能双向交流。您需要将父级的实例传递给子级,但我认为传递实例不是正确的方法。

最好的方法是什么?

这里以一些代码为例,希望它清楚(请阅读代码中的cmets以更好地理解):

class MainWindow:
    def __init__(self, master, username, sock):
        # Tkinter Code Here

    def insert_msg(self, data):  # d_type 1 - msg
        self.chat_textbox.insert(END, "\n%s %s" % (datetime.now().strftime('%H:%M:%S'), data))
        self.chat_textbox.see(END)

    def send_msg(self, data, d_type=SEND_ENUM.TYPE_MSG, arg=0):
        data = str(data)
        if len(data) >= 1 and d_type == SEND_ENUM.TYPE_MSG:
            try:
                self.chat_textbox.insert(END, "\n%s [Me] %s" % (datetime.now().strftime('%H:%M:%S'), data))

                # For example, here has to use send_msg method from SockHandler class
                # self.sock_handler.send_msg(data)

            except sock_handling.ConnectionError as error:
                self.chat_textbox.insert(END, "\nError: The message was not delivered", "RED")
            else:
                pass
            finally:
                self.msg_box_entry.delete(0, 'end')
                self.chat_textbox.see(END)
        elif d_type != SEND_ENUM.TYPE_MSG:
            try:
                # also here self.sock_handler.send_msg(data, d_type)
            except sock_handling.ConnectionError as error:
                pass
        else:
            pass

class SockHandler:
    def __init__(self, client_socket):
        # nothing relevant for the Q

    def send_msg(self, data, d_type=SEND_ENUM.TYPE_MSG, arg=0):
        packed_data = self.pack_data(d_type, arg, data)

        if len(data) >= 1 and d_type == SEND_ENUM.TYPE_MSG:
            try:
                self.client_socket.send(packed_data)
            except socket.error:
                raise ConnectionError("Connection Error")

            finally:
                pass

        elif d_type != SEND_ENUM.TYPE_MSG:
            try:
                self.client_socket.send(packed_data)
            except socket.error:
                raise ConnectionError("Connection Error")

    def receive_data(self):
        try:
            while True:
                recv_data = self.client_socket.recv(self.BUFFER)
                (d_type,), data = struct.unpack("!I", recv_data[:4]), recv_data[4:]
                if d_type == RECV_ENUM.TYPE_MSG:

                    # For example, here has to use insert_msg method from MainWindow class

                elif d_type == RECV_ENUM.TYPE_USER_LIST:
                    pass
                elif d_type == RECV_ENUM.TYPE_POKE:
                    pass
        except socket.error:
            self.client_socket.close()
            raise ConnectionError("Connection Error")

【问题讨论】:

    标签: python oop logic


    【解决方案1】:

    为什么不将SockHandler 实例化为MainWindow 的属性?

    像这样:

    class MainWindow:
        def __init__(self, master, username, sock):
            # Tkinter Code Here
            self.socket_handler = SockHandler(sock)
    

    现在您可以使用self.socket_handler.send_msgMainWindow 发送消息

    为了接收,让您的套接字将接收到的数据存储在MainWindow 可以检索到的位置。

    像这样:

    class SockHandler:
        def __init__(self, client_socket):
            # nothing relevant for the Q
            self.received_messages = Queue.Queue()
    

    现在您需要为MainWindow 公开一种访问接收到的消息的方法。如果你愿意,你可以让它通过查询队列直接获取消息,但我更喜欢这样的:

    # Within the SockHandler Class
    def get_next_message():
        try:
            return self.received_messages.get(True, 5)
        except:
            return None
    

    SockHandlerMainWindow 是否在此方法中处理 Timeout 异常无关紧要。这取决于你。

    【讨论】:

      猜你喜欢
      • 2014-05-24
      • 1970-01-01
      • 2012-06-03
      • 2017-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多