PySide2:如何使装饰槽在其工作线程上执行?
PySide2: How to make a decorated slot execute on its worker thread?
使用 Python 3.7 和 PySide2,我创建了一个 worker object on a dedicated QThread 来执行 long-运行ning 函数。下面的代码对此进行了说明。
import threading
from time import sleep
from PySide2.QtCore import QObject, QThread, Signal, Slot
from PySide2.QtWidgets import QApplication
class Main(QObject):
signal_for_function = Signal()
def __init__(self):
print('The main thread is "%s"' % threading.current_thread().name)
super().__init__()
self.thread = QThread(self)
self.worker = Worker()
self.worker.moveToThread(self.thread)
self.thread.start()
self.signal_for_function.connect(self.worker.some_function)
def some_decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
class Worker(QObject):
# @some_decorator
def some_function(self):
print('some_function is running on thread "%s"' % threading.current_thread().name)
app = QApplication()
m = Main()
m.signal_for_function.emit()
sleep(0.100)
m.thread.quit()
m.thread.wait()
如果我在没有装饰器的情况下使用 some_function,我会按预期得到:
The main thread is "MainThread"
some_function is running on thread "Dummy-1"
但是,如果我应用装饰器(即取消注释“@some_decorator”),我得到:
The main thread is "MainThread"
some_function is running on thread "MainThread"
为什么会发生这种情况,如何按照我的意图在工作线程上创建修饰函数 运行?
解决方案:
您必须使用 @functools.wrap
:
<b>import functools</b>
# ...
def some_decorator(func):
<b>@functools.wraps(func)</b>
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
输出:
The main thread is "MainThread"
some_function is running on thread "Dummy-1"
解释:
要分析是否使用@functools.wrap
的区别,则必须使用以下代码:
def some_decorator(func):
print(func.__name__, func.__module__, func.__doc__, func.__dict__)
@functools.wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
print(wrapper.__name__, wrapper.__module__, wrapper.__doc__, wrapper.__dict__)
return wrapper
通过删除 @functools.wrap
,您应该得到以下内容:
some_function __main__ None {}
wrapper __main__ None {}
如果不删除 @functools.wrap
,您应该得到以下内容:
some_function __main__ None {}
some_function __main__ None {'__wrapped__': <function Worker.some_function at 0x7f610d926a60>}
主要区别在于 __name__,在 @functools.wrap 的情况下,它使包装函数与 "func" 具有相同的名称,这有什么区别?用于判断该函数是否属于Workerclass,即创建Workerclass时,会创建一个字典,其中存放方法、属性等,但当信号调用 some_function 然后它 returns 名称为 "wrapper" 的包装器不在 Worker 的字典中,但在使用 @functools.wrapper [=42= 的情况下] 被调用,然后它 returns 包装名称 "some_function" 导致 Worker 对象调用它。
使用 Python 3.7 和 PySide2,我创建了一个 worker object on a dedicated QThread 来执行 long-运行ning 函数。下面的代码对此进行了说明。
import threading
from time import sleep
from PySide2.QtCore import QObject, QThread, Signal, Slot
from PySide2.QtWidgets import QApplication
class Main(QObject):
signal_for_function = Signal()
def __init__(self):
print('The main thread is "%s"' % threading.current_thread().name)
super().__init__()
self.thread = QThread(self)
self.worker = Worker()
self.worker.moveToThread(self.thread)
self.thread.start()
self.signal_for_function.connect(self.worker.some_function)
def some_decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
class Worker(QObject):
# @some_decorator
def some_function(self):
print('some_function is running on thread "%s"' % threading.current_thread().name)
app = QApplication()
m = Main()
m.signal_for_function.emit()
sleep(0.100)
m.thread.quit()
m.thread.wait()
如果我在没有装饰器的情况下使用 some_function,我会按预期得到:
The main thread is "MainThread"
some_function is running on thread "Dummy-1"
但是,如果我应用装饰器(即取消注释“@some_decorator”),我得到:
The main thread is "MainThread"
some_function is running on thread "MainThread"
为什么会发生这种情况,如何按照我的意图在工作线程上创建修饰函数 运行?
解决方案:
您必须使用 @functools.wrap
:
<b>import functools</b>
# ...
def some_decorator(func):
<b>@functools.wraps(func)</b>
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
输出:
The main thread is "MainThread"
some_function is running on thread "Dummy-1"
解释:
要分析是否使用@functools.wrap
的区别,则必须使用以下代码:
def some_decorator(func):
print(func.__name__, func.__module__, func.__doc__, func.__dict__)
@functools.wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
print(wrapper.__name__, wrapper.__module__, wrapper.__doc__, wrapper.__dict__)
return wrapper
通过删除 @functools.wrap
,您应该得到以下内容:
some_function __main__ None {}
wrapper __main__ None {}
如果不删除 @functools.wrap
,您应该得到以下内容:
some_function __main__ None {}
some_function __main__ None {'__wrapped__': <function Worker.some_function at 0x7f610d926a60>}
主要区别在于 __name__,在 @functools.wrap 的情况下,它使包装函数与 "func" 具有相同的名称,这有什么区别?用于判断该函数是否属于Workerclass,即创建Workerclass时,会创建一个字典,其中存放方法、属性等,但当信号调用 some_function 然后它 returns 名称为 "wrapper" 的包装器不在 Worker 的字典中,但在使用 @functools.wrapper [=42= 的情况下] 被调用,然后它 returns 包装名称 "some_function" 导致 Worker 对象调用它。