在不同线程中使用 class attributes/methods - Python
Using class attributes/methods across different threads - Python
我会尽力以清晰的方式解释这个问题,它是我为 A 级项目开发的一个更大的软件的一部分——一个旨在创建一个简单的项目的项目图形化编程系统的版本(想想猴子用大约 7 个命令制作的 scratch)。
我目前的麻烦源于需要在一个独特的线程上执行 运行ning 函数,该线程能够与用户界面交互,显示用户编写的代码块的执行结果(使用 Tkinter 库编写)在主线程上。此函数旨在遍历一个动态列表,该列表包含有关用户 "code" 的信息,其形式可以循环遍历并处理 "line by line".
问题发生在执行开始时,线程函数尝试调用属于用户界面一部分的函数 class。我对多线程的理解有限,所以很可能我违反了一些重要的规则并以没有意义的方式做事,在这里提供帮助会很棒。
我已经实现了接近我之前所追求的功能,但总是会以不同的方式出现一些错误(主要是由于我最初尝试在第二个线程中打开 tkinter window...a馊主意)。
据我所知,我当前的代码在打开第二个线程、在主线程中打开 UI 并在第二个线程中开始 运行 执行函数方面起作用线。为了解释这个问题,我创建了一小段代码,它在相同的基础上工作,并产生相同的 "none type" 错误,我会使用原始代码,但它很笨重,而且更烦人关注以下内容:
from tkinter import *
import threading
#Represents what would be my main code
class MainClass():
#attributes for instances of each of the other classes
outputUI = None
threadingObject = None
#attempt to open second thread and the output ui
def beginExecute(self):
self.threadingObject = ThreadingClass()
self.outputUI = OutputUI()
#called by function of the threaded class, attempts to refer to instance
#of "outputUI" created in the "begin execute" function
def execute(self):
return self.outputUI.functionThatReturns()
#class for the output ui - just a blank box
class OutputUI():
#constructor to make a window
def __init__(self):
root = Tk()
root.title = ("Window in main thread")
root.mainloop()
#function to return a string when called
def functionThatReturns(self):
return("I'm a real object, look I exist! Maybe")
#inherits from threading library, contains threading... (this is where my
#understanding gets more patchy)
class ThreadingClass(threading.Thread):
#constructor - create new thread, run the thread...
def __init__(self):
threading.Thread.__init__(self)
self.start()
#auto called by self.start() ^ (as far as I'm aware)
def run(self):
#attempt to run the main classes "execute" function
print(mainClass.execute())
#create instance of the main class, then attempt execution of some
#threading
mainClass = MainClass()
mainClass.beginExecute()
当此代码为 运行 时,会产生以下结果:
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Python34\lib\threading.py", line 920, in _bootstrap_inner
self.run()
File "H:/Programs/Python/more more threading tests.py", line 33, in run
print(mainClass.execute())
File "H:/Programs/Python/more more threading tests.py", line 14, in execute
return self.outputUI.functionThatReturns()
AttributeError: 'NoneType' object has no attribute 'functionThatReturns'
我想应该注意的是 tkinter window 如我所愿打开,线程 class 做了它应该做的,但似乎没有意识到输出 UI。我认为这是由于我对面向对象和线程的某些部分知之甚少造成的。
那么,有没有一种方法可以从线程函数中调用输出 ui 中的函数?或者是否有类似的解决方法?
需要注意的是,我没有将输出 window 的创建放在 main class 的 init 函数中,因为我需要能够创建输出 window 并根据另一个输入开始线程等。
抱歉,如果这没有意义,请对我大喊大叫,我会尝试修复它,但我们将不胜感激,干杯。
这里的问题是你的操作顺序。您在 MainClass.beginExecute()
中创建一个 ThreadingClass
,它调用 self.start()
。调用 run
最终会尝试调用 main.outputUI
上的函数。但是 main.outputUI
还没有被初始化(那是 beginExecute()
中的 next 行)。您可能只需重新排序这两行即可使其工作。但是您可能不想在线程的 __init__
中调用 self.start()
。这看起来很糟糕。
我会尽力以清晰的方式解释这个问题,它是我为 A 级项目开发的一个更大的软件的一部分——一个旨在创建一个简单的项目的项目图形化编程系统的版本(想想猴子用大约 7 个命令制作的 scratch)。
我目前的麻烦源于需要在一个独特的线程上执行 运行ning 函数,该线程能够与用户界面交互,显示用户编写的代码块的执行结果(使用 Tkinter 库编写)在主线程上。此函数旨在遍历一个动态列表,该列表包含有关用户 "code" 的信息,其形式可以循环遍历并处理 "line by line".
问题发生在执行开始时,线程函数尝试调用属于用户界面一部分的函数 class。我对多线程的理解有限,所以很可能我违反了一些重要的规则并以没有意义的方式做事,在这里提供帮助会很棒。
我已经实现了接近我之前所追求的功能,但总是会以不同的方式出现一些错误(主要是由于我最初尝试在第二个线程中打开 tkinter window...a馊主意)。
据我所知,我当前的代码在打开第二个线程、在主线程中打开 UI 并在第二个线程中开始 运行 执行函数方面起作用线。为了解释这个问题,我创建了一小段代码,它在相同的基础上工作,并产生相同的 "none type" 错误,我会使用原始代码,但它很笨重,而且更烦人关注以下内容:
from tkinter import *
import threading
#Represents what would be my main code
class MainClass():
#attributes for instances of each of the other classes
outputUI = None
threadingObject = None
#attempt to open second thread and the output ui
def beginExecute(self):
self.threadingObject = ThreadingClass()
self.outputUI = OutputUI()
#called by function of the threaded class, attempts to refer to instance
#of "outputUI" created in the "begin execute" function
def execute(self):
return self.outputUI.functionThatReturns()
#class for the output ui - just a blank box
class OutputUI():
#constructor to make a window
def __init__(self):
root = Tk()
root.title = ("Window in main thread")
root.mainloop()
#function to return a string when called
def functionThatReturns(self):
return("I'm a real object, look I exist! Maybe")
#inherits from threading library, contains threading... (this is where my
#understanding gets more patchy)
class ThreadingClass(threading.Thread):
#constructor - create new thread, run the thread...
def __init__(self):
threading.Thread.__init__(self)
self.start()
#auto called by self.start() ^ (as far as I'm aware)
def run(self):
#attempt to run the main classes "execute" function
print(mainClass.execute())
#create instance of the main class, then attempt execution of some
#threading
mainClass = MainClass()
mainClass.beginExecute()
当此代码为 运行 时,会产生以下结果:
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Python34\lib\threading.py", line 920, in _bootstrap_inner
self.run()
File "H:/Programs/Python/more more threading tests.py", line 33, in run
print(mainClass.execute())
File "H:/Programs/Python/more more threading tests.py", line 14, in execute
return self.outputUI.functionThatReturns()
AttributeError: 'NoneType' object has no attribute 'functionThatReturns'
我想应该注意的是 tkinter window 如我所愿打开,线程 class 做了它应该做的,但似乎没有意识到输出 UI。我认为这是由于我对面向对象和线程的某些部分知之甚少造成的。
那么,有没有一种方法可以从线程函数中调用输出 ui 中的函数?或者是否有类似的解决方法? 需要注意的是,我没有将输出 window 的创建放在 main class 的 init 函数中,因为我需要能够创建输出 window 并根据另一个输入开始线程等。
抱歉,如果这没有意义,请对我大喊大叫,我会尝试修复它,但我们将不胜感激,干杯。
这里的问题是你的操作顺序。您在 MainClass.beginExecute()
中创建一个 ThreadingClass
,它调用 self.start()
。调用 run
最终会尝试调用 main.outputUI
上的函数。但是 main.outputUI
还没有被初始化(那是 beginExecute()
中的 next 行)。您可能只需重新排序这两行即可使其工作。但是您可能不想在线程的 __init__
中调用 self.start()
。这看起来很糟糕。