簡體   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