1. Intro
I'm working with PyQt5
in Python 3.7 on a multithreaded application, for which I rely on the QThread
.
Now suppose I have a class derived from QObject
. Within that class, I define a function annotated with @pyqtSlot
:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import threading
...
class Worker(QObject):
def __init__(self):
super().__init__()
return
@pyqtSlot()
def some_function(self):
...
return
In some other code, I instantiate Worker()
and move it to a new thread, like so:
my_thread = QThread()
my_worker = Worker()
my_worker.moveToThread(my_thread)
my_thread.start()
QTimer.singleShot(100, my_worker.some_function)
return
Normally, some_function()
should now run in my_thread
. That's because:
- I've pushed the
Worker()
object tomy_thread
. - When commanding
my_thread
to start, I've actually given birth to a new Qt event-loop in that thread. Themy_worker
object lives in this event-loop. All its slots can receive an event, which gets executed in this event-loop. some_function()
is properly annotated to be a@pyqtSlot()
. The single-shot-timer hooks onto this slot and fires an event. Thanks to the Qt-event-loop inmy_thread
, the slot effectively executes its code inmy_thread
.
2. My question
My question is about nested functions (also called 'inner functions'). Consider this:
class Worker(QObject):
def __init__(self):
super().__init__()
return
def some_function(self):
...
@pyqtSlot()
def some_inner_function():
...
return
return
As you can see, some_inner_function()
is annotated as @pyqtSlot
. Will its code also run in the thread the Worker()
-object lives in?
3. Sidenote: how to hook to the inner function
You might wonder how I could hook something to the inner function. Well, consider the following:
class Worker(QObject):
def __init__(self):
super().__init__()
return
def some_function(self):
@pyqtSlot()
def some_inner_function():
# Will this code run in `my_thread`?
...
return
# some_function() will run in the main thread if
# it is called directly from the main thread.
QTimer.singleShot(100, some_inner_function)
return
If you call some_function()
directly from the main thread, it will (unfortunately) run in the main thread. Without properly using the signal-slot mechanism, you won't switch threads.
The single-shot-timer inside some_function()
hooks onto some_inner_function()
and fires. Will the inner function execute in my_thread
(supposing that the Worker()
-object was assigned to my_thread
)?