繁体   English   中英

Python线程和全局变量

[英]Python threads and global variables

我有一个类,其中第一个方法中的一些变量声明为全局变量。 另一个随后的方法启动一个线程,问题是python在t.start()之后不能识别那些全局变量。 该程序的工作原理如下:1)用户可以在tkinter窗口上单击“是”按钮2)程序然后开始将数据上传到数据库中。 此步骤需要一些时间(2-5分钟),并且为防止UI在上载期间冻结,该程序启动了一个执行sql内容的线程。 同时,程序从窗口中清除小部件,并用新的小部件(进度条和文本字段)替换它们。 3)上传完成后,程序再次使用新按钮和滚动框刷新tkinter窗口。

这是代码片段:

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

它只会引发以下错误消息:

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

为什么? 如您所见,我可以在声明它们的方法之外调用这些变量。 这与线程有关吗?我不太熟悉吗?

除非我不会忘记这些text2和进度条小部件,否则它们将显示在不需要的功能的最后一个窗口中。

您应该在removeButtonYes方法上添加global text2 (以及progress_bar ,否则会再次遇到相同的问题)。 在未定义该变量的函数中添加global text2语句完全没有用。

我也看不到在这种情况下使用全局变量的优势,除了创建bug确实很容易。 为什么不简单使用实例属性self.text2self.progress_bar

global语句不会创建全局。 它仅表示对给定名称的分配是在全局上下文而不是本地上下文中进行分配。 这也意味着名称访问将获得全局变量,而不是局部变量。 如果您仅访问全局变量,则python能够确定该变量是全局变量,而不是局部变量,而不需要global语句。

例如。

def adder(to_add):
    global total
    total = total + to_add
    return total

try:
    # total does not exist at this point
    adder(1)
except NameError as e:
    print(e)

total = 10
print(adder(4))

您的问题是您声明了text2为全局text2 ,但未将其分配给text2 ,因此从未在全局上下文中创建名称text2

当您稍后将方法分配给text2它们将在方法的本地上下文中创建名称(因为此处未将text2声明为全局名称)。 一种方法结束,取消引用Label对象并收集垃圾。

不过,您实际上确实不需要使用全局变量。 您有一个Application实例(在您的方法中称为self ),可以将您的对象分配给该实例。 如果您需要在Application实例之外访问这些对象,真的很容易

例如。

app = Application() # assigns some object to text2 on self
app.text2.pack()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM