我有一个类,在第一个方法中将一些变量声明为全局变量。另一个后续方法启动一个线程,问题是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和进度条小部件,否则它们将显示在最后一个不需要的功能窗口中。
答案 0 :(得分:2)
您应该在global text2
方法上添加removeButtonYes
(也适用于progress_bar
,否则您将再次遇到同样的问题)。在一个没有定义该变量的函数中添加global text2
语句是完全没用的。
此外,我没有看到在这种情况下使用全局变量的优势,除了它很容易创建错误。为什么不简单地使用实例属性self.text2
和self.progress_bar
?
答案 1 :(得分:0)
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
未声明为全局)。一个方法结束,Label
对象被解除引用并被垃圾收集。
你真的没有必要使用全局变量。您有一个Application
(在您的方法中称为self
)的实例,您可以将对象分配给该实例。如果需要
Application
实例之外访问这些对象非常容易
例如
app = Application() # assigns some object to text2 on self
app.text2.pack()