How to share data between two classes

2019-03-06 07:52发布

问题:

Question

Is there a way to have two classes simultaneously inherit from one another?

Background

I am currently working on a Socket Server project. In this project, I have a two classes, a Server class, and a GUI class. Their purposes are self explanatory. But, I obviously need to have the two classes communicate with one another. In the program, I first declare the Socket_Server class, and then the GUI class.

I asked a similar question, How to Access Functions from Methods in Python, which was never satisfactorily answered. Please try to answer either.

Code and Errors

In the GUI class, I have a textbox called self.message. It is used to send a message to all clients. I attempted to inherit this class by using this syntax:

class Socket_Server(GUI.messageFun):

Next, the GUI class inherits from the Socket_Server -

class GUI(Frame, Socket_Server): 

The second inheritance GUI(Socket_Server) works correctly, but the first one fails.

The Button's command is this

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

new_server is an instance of the Socket_Server class.

The current Error Message is this:

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'

回答1:

The title of this question is different (and a bit more accurate) than the question you ask at the beginning, but none of them fit with what you want. What you need is to communicate two instances of different classes; that is not inheritance.

When you use inheritance, you should ask yourself if every X is also an Y:

  • Is every Employee a Person? Yes
  • Is every Person an Employee? No
  • Is every Employee a Car? No

With this concept in mind, you may see the third example is the most similar to the relation between GUI and Server. It is because your real question is:

  • Does a GUI instance use a Server object?

If the answer is yes, then the server should be an attribute of your GUI class. In the following example, you can see that GUI calls methods of the Server object, but not the other way around:

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

Edit: This code looks more like a client than a server, so it may be a good idea to rename it to something more similar to the concept you have in mind (e.g., Notifier)



回答2:

The thing you are having trouble with is object orientation. You need to go look up how inheritance works, how objects interact and so fourth its a bit of a hefty subject to cover in one post and is going to take experience to get your head around it.

A side note about tkinter, The command property is Button takes a reference. This is so that every time the button is clicked it will call that function.

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

That is saying that command equals the result of new_server.send_cmd().

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

This one is saying that command equals a refernce to the send_cmd method.