0

I have code structure something like this:-

def send_message(msg):
    print msg + "\n"
    x.new_message("You",msg)


class GUI(Frame):

def createWidgets(self):
    self.input.bind('<Key-Return>',self.send)

def send(self, event):
    send_message(self.contents.get())
    self.contents.set("")
def new_message(self,sender, msg):
    line = sender+": "+msg+"\n"
    self.chat.contents.set(self.chat.contents.get()+line)

def __init__(self):
    self.createWidgets()

x = GUI()

As you can see, this has some circular dependancies. Function send_message requires instance x as well as new_message method of GUI. GUI definition needs send_message. Thus it is not possible to satisfy all the constraints. What to do?

Meet Taraviya
  • 869
  • 1
  • 8
  • 27
  • Have you tried to run the code? – syntonym Apr 10 '17 at 13:34
  • Is there any reason that ``send_message`` cannot be a method on GUI? – James Elderfield Apr 10 '17 at 13:34
  • @syntonym This is not the entire code. I have removed parts not relevant to question. I ran the code while declaring them in different orders, but they were giving "xxx not defined" errors – Meet Taraviya Apr 10 '17 at 13:38
  • @JamesElderfield I am making a chat client, and want to separate GUI implementation from networking implementations. send_message is a function related to the networking part. I can come up with a work around, but that would be ugly. – Meet Taraviya Apr 10 '17 at 13:39
  • The code you showed does not produce the error for me. Python is "latebinding", i.e. attributes are only looked up when you call the function, not when defining the function. – syntonym Apr 10 '17 at 13:42
  • @syntonym Yes you are correct. But I am getting the following error only when send_message is called : global name 'x' is not defined – Meet Taraviya Apr 10 '17 at 13:49
  • So does a global variable named `x` exists? Is `x = GUI()` in the proper scope and is it executed before you try to call `send_message`? – syntonym Apr 10 '17 at 13:52
  • @syntonym The order is just as shown. These are the contents of a single main file. – Meet Taraviya Apr 10 '17 at 13:54
  • @syntonym You can have a look at the actual code : https://pastebin.com/jeSXU5ci – Meet Taraviya Apr 10 '17 at 14:00
  • @MeetTaraviya In `GUI.__init__` you call `mainloop()`. I don't really know tkinter, but I guess that starts the event detection etc. `x = GUI()` will only finish after `__init__` finishes, but because you call the mainloop there it will only finish after the program finished. Especially `x = ..` will not finish before you try to send a message. – syntonym Apr 10 '17 at 14:03
  • That seems convincing. Possibly mainloop creates a new thread and 'x' is not defined in its scope. How to deal with it? – Meet Taraviya Apr 10 '17 at 14:11
  • Call `mainloop()` after you initialized the GUI. Or change the function `send_message` so that you have to pass the gui into it. Or move the function to the GUI class. – syntonym Apr 10 '17 at 14:18

2 Answers2

0

Names within Python functions are not required to refer to anything at the time the function is defined - they're only looked up when the function is actually called. So, your send_message() is perfectly fine as it is (although it would probably be better to make x a parameter rather than a global variable).

Your GUI class is going to fail to instantiate as shown, due to references to widgets you didn't show the creation of - self.input for example. I cannot tell how much of that is due to you stripping the code down for posting.

jasonharper
  • 9,450
  • 2
  • 18
  • 42
  • Don't worry about other things I know they work. I have stripped down the code to bare minimal. Now, I don't understand what you say. In what order should I define the variables? – Meet Taraviya Apr 10 '17 at 13:47
0

In the complete code you showed in die comments we can see that you call self.mainloop() in GUI.__init__. This will start the event handling of the gui and will probably not terminate until the program in finished. Only then the assignment x = GUI() will finish and x will be available.

To circumvent this you have multiple options. Generally doing an endless loop in __init__ is probably a bad idea. Instead call mainloop() after the GUI is instantiated.

def __init__(self):
    # only do init

x = GUI()
x.mainloop()

As jasonharper said in python variables in functions are only looked up when you execute that function, not when defining them. Thus circular dependencies in runtime are most of the time not a problem in python.

syntonym
  • 7,134
  • 2
  • 32
  • 45
  • But if I do so, where should I add other code? As I said, this is not the complete code and there are many things that I need to call in main after x.mainloop() – Meet Taraviya Apr 10 '17 at 15:21
  • What exactly do you need to call? You cannot call anything after the mainloop, well atleast nothing that you would need in the mainloop. Of course you can do desctructors, closing files, etc. See also [this question](https://stackoverflow.com/questions/8683217/when-do-i-need-to-call-mainloop-in-a-tkinter-application) – syntonym Apr 10 '17 at 15:41