如何在两个类之间共享数据

0 投票
2 回答
3138 浏览
提问于 2025-04-17 18:33

问题

有没有办法让两个类同时互相继承呢?

背景

我现在在做一个Socket服务器项目。在这个项目中,我有两个类,一个是Server类,另一个是GUI类。它们的功能很明显。但我显然需要让这两个类能够互相沟通。在程序中,我先声明Socket_Server类,然后再声明GUI类。

我之前问过一个类似的问题,如何在Python中访问方法中的函数,但没有得到满意的回答。希望你们能尝试回答这个问题。

代码和错误

GUI类中,我有一个文本框叫self.message。它用于向所有客户端发送消息。我尝试用以下语法来继承这个类:

class Socket_Server(GUI.messageFun):

接下来,GUI类继承自Socket_Server -

class GUI(Frame, Socket_Server): 

第二个继承GUI(Socket_Server)是正确的,但第一个继承失败了。

按钮的命令是这个

        self.send = Button (self.messageFrame, text = "Send",
                        command = lambda: new_server.send_cmd()) 

new_serverSocket_Server类的一个实例。

当前的错误信息是:

Socket Created
Socket Bind Complete
Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python27\lib\lib-tk\Tkinter.py", line 1410, in __call__
    return self.func(*args)
  File "D:\Python Programs\Sockets\IM Project\Server\Server GUI InDev Class.py", line 129, in <lambda>
    command = lambda: new_server.send_cmd())
  File "D:\Python Programs\Sockets\IM Project\Server\Server GUI InDev Class.py", line 82, in send_cmd
    message = self.message.get("0.0",END)
AttributeError: Socket_Server instance has no attribute 'message'

2 个回答

0

你遇到的问题是关于面向对象编程的。你需要去了解一下继承是怎么回事,对象之间是如何互动的等等。这些内容比较复杂,没法在一篇文章里全部讲清楚,需要一些经验才能理解。

关于tkinter的一个小提示,Button的command属性是一个引用。这意味着每次点击按钮时,它都会调用那个函数。

self.send = Button (self.messageFrame, text = "Send",
                        command = new_server.send_cmd())

这段代码的意思是command等于new_server.send_cmd()的结果。

self.send = Button (self.messageFrame, text = "Send",
                    command = new_server.send_cmd)

而这一段的意思是command等于send_cmd方法的引用。

2

这个问题的标题和你一开始问的内容有点不同(而且更准确),但都不太符合你想要的。你需要的是让两个不同类的实例进行沟通;这并不是继承的概念。

当你使用继承时,应该问自己每个X是否也是一个Y:

  • 每个Employee都是Person吗?是的
  • 每个Person都是Employee吗?不是
  • 每个Employee都是Car吗?不是

理解了这个概念后,你会发现第三个例子和GUIServer之间的关系最为相似。因为你真正想问的是:

  • 一个GUI实例是否使用一个Server对象?

如果答案是“是”,那么服务器应该是你的GUI类的一个属性。在下面的例子中,你可以看到GUI调用了Server对象的方法,而不是反过来:

import Tkinter as tk
import threading
import socket

class Server():
    def __init__(self):
        self.addresses = [('localhost', 12345)] # All addresses to send data
    def sendtoall(self, data):
        for address in self.addresses:
            self._send(address, data)
    def _send(self, address, data):
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect(address)
            sock.sendall(data)
        finally:
            sock.close()

class GUI(tk.Tk):
    def __init__(self, server):
        tk.Tk.__init__(self)
        self.server = server
        self.entry = tk.Entry(self)
        self.button = tk.Button(self, text="Send", command= self.sendmessage)
        self.entry.pack()
        self.button.pack()
    def sendmessage(self):
        message = self.entry.get()
        threading.Thread(target=self.server.sendtoall, args=(message,)).start()

server = Server()
gui = GUI(server)
gui.mainloop()

编辑:这段代码看起来更像是一个客户端而不是服务器,所以把它改名为更符合你想法的名称(例如,Notifier)可能是个好主意。

撰写回答