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