Python threads and global variables

advertisements

I have a class with some variables declared as globals in the first method. Another subsequent method starts a thread, and the problem is that python doesn't recognize those global variables after t.start(). Here is how the program works: 1) user can click "YES"-button on tkinter window 2) program then starts to upload data into database. This step takes a while (2-5 minutes) and to prevent UI from freezing during the upload, the program starts a thread that performs the sql stuff. At same time, the program clears widgets from the window and replaces them with new widgets (a progress bar and a text field). 3) after upload is completed, the program again refresh the tkinter window with new buttons and a scrollbox.

Here is the code snippet:

class Application(tk.Frame):

    def __init__(self, parent):
      #do some init here..

    def initUI(self):
        global text1, text2, button_no, button_yes, progress_bar #here are the globals
        frame1 = tk.Frame(self)
        frame1.pack()
        text1 = tk.Label(self, text="Do you want to upload a new log file?", background="white")
        button_yes = tk.Button(self, text="YES", command=self.removeButtonYes)
        button_no = tk.Button(self, text="NO", command=self.removeButtonNo)
        text1.pack()
        button_yes.pack()
        button_no.pack()
        self.pack(fill=tk.BOTH, expand=1)

    def removeButtonNo(self):
#do something here

    def removeButtonYes(self):
        text1.pack_forget() #first three lines clear those original three widgets
        button_no.pack_forget()
        button_yes.pack_forget()
#then add some text with the progress bar
        text2 = tk.Label(self, text="Transferring data. Please wait...", background="white")
        text2.pack()
        progress_bar = ttk.Progressbar(self, orient="horizontal", length=100, mode="indeterminate")
        progress_bar.pack()
        progress_bar.start(100)
        #initialize a thread to prevent the UI from freezing during sql inserts
        t = threading.Thread(target=self.writeLogtoDatabase)
        t.start()

    def writeLogtoDatabase(self):
        #open db connection, upload data and close db
        self.clearUI() #call a method to clear the progress bar and info text

    def clearUI(self):
        text2.pack_forget()
        progress_bar.pack_forget()

It just throws following error message:

Exception in thread Thread-1:
Traceback (most recent call last):
  File "c:\python27\lib\threading.py", line 810, in __bootstrap_inner
    self.run()
  File "c:\python27\lib\threading.py", line 763, in run
    self.__target(*self.__args, **self.__kwargs)
  File "C:\Python27\test\testdb2.py", line 94, in writeLogtoDatabase
    self.clearUI()
  File "C:\Python27\test\testdb2.py", line 98, in clearUI
    text2.pack_forget()
NameError: global name 'text2' is not defined

Why? As you can see, I can call those variables outside the method where they are declared. Has this something to do with threading - a thing, that I am not very familiar with?

Unless I don't forget those text2 and progress bar widgets, they will show up in the last window which is not desired functionality.


You should add global text2 on the removeButtonYes method (and also for progress_bar, otherwise you'll have the same problem again). It's completely useless to add a global text2 statement in a function that doesn't define that variable.

Also I don't see the advantage of using a global variable in this case, except that it's really easy to create bugs. Why don't you simply use an instance attribute self.text2 and self.progress_bar?