英文:
How to correctly type-hint a function with `pyqtSlot()` decorator inside `QRunnable` class?
问题
状态:
- 我正在学习如何在
PyQt
库中使用并发/线程,教程来源于www.pythonguis.com。以下是该教程中的简化/部分代码。 - 我希望在我的代码中使用严格的类型提示。但是我在这段代码中使用
mypy
时遇到了错误消息(在第二个源代码块中显示)。
问题:
- 在使用
pyqtSlot()
装饰器时,如何正确地为函数添加类型提示? - 在这种情况下,
Superclass
(返回None
)和Subclass
(返回str|None
)分别是什么?
我尝试解决的问题:
- 我对错误消息感到不满意,这让我很困扰。我浪费了太多时间来解决一行代码的问题。我在互联网上找不到有用的信息。
- 定义(或者说
stub
文件)中说pyqtSlot()
是这样的:
def pyqtSlot(*types, name: typing.Optional[str] = ..., result: typing.Optional[str] = ...) -> typing.Callable[..., typing.Optional[str]]: ...
,由于我对装饰器没有经验,我无法解释这个定义。 stub
文件:QtCore.pyi
中说Class QRunnable
的run
方法是这样的:def run(self) -> None: ...
。
from typing import Callable
from PyQt5.QtCore import QObject, QRunnable, pyqtSignal, pyqtSlot
import traceback
import sys
class WorkerSignal(QObject):
finished = pyqtSignal()
error = pyqtSignal(tuple)
result = pyqtSignal(object)
progress = pyqtSignal(int)
class Worker(QRunnable):
def __init__(self, fn: Callable[[], str]) -> None:
super(Worker, self).__init__()
self.fn: Callable[[], str] = fn
self.signals: WorkerSignal = WorkerSignal()
@pyqtSlot()
def run(self) -> None: # <====================== 这一行
try:
result: str = self.fn()
except Exception:
traceback.print_exc()
exctype, value = sys.exc_info()[:2]
self.signals.error.emit((exctype, value, traceback.format_exc()))
else:
self.signals.result.emit(result)
finally:
self.signals.finished.emit()
$ mypy /tmp/tmp.py
/tmp/tmp.py:22: error: Signature of "run" incompatible with supertype "QRunnable" [override]
/tmp/tmp.py:22: note: Superclass:
/tmp/tmp.py:22: note: def run(self) -> None
/tmp/tmp.py:22: note: Subclass:
/tmp/tmp.py:22: note: str | None
Found 1 error in 1 file (checked 1 source file)
编辑:
-
以下猜测是否正确?
pyqtSlot()
接受返回类型为typing.Optional[str]
(即str | None
)的函数。也许这是subclass
?QRunnable
的run()
方法只返回None
,也许这是superclass
?- 在这种情况下,正确的问题应该是:如果
装饰器的返回值
和函数的返回值
不同,如何使用装饰器?这个问题是否正确?
英文:
Status:
- I'm learning how to use concurrency/threads within
PyQt
library from here www.pythonguis.com. Below is the simplified/part of code from this tutorial. - I want strict type hinting in my code. And I'm getting error messages on this code from
mypy
. (Shown on the 2-nd source-code block).
Question:
- How to correctly type-hint the function while using
pyqtSlot()
decorator? - What is
Superclass
(that returnNone
), and what isSubclass
(that returnsstr|None
) in this case?
What I tried to solve:
- My autistic ass doesn't sit well with error is showing on my text-editor. And I wasted too much time to solve single line. I couldn't find anything useful on the internet.
- The definition (or should I say
stub
file) sayspyqtSlot()
is:
def pyqtSlot(*types, name: typing.Optional[str] = ..., result: typing.Optional[str] = ...) -> typing.Callable[..., typing.Optional[str]]: ...
, I'm unable to interpret this due to no-experience on decorators. stub
file:QtCore.pyi
says thatClass QRunnable
'srun
is:def run(self) -> None: ...
.
from typing import Callable
from PyQt5.QtCore import QObject, QRunnable, pyqtSignal, pyqtSlot
import traceback
import sys
class WorkerSignal(QObject):
finished = pyqtSignal()
error = pyqtSignal(tuple)
result = pyqtSignal(object)
progress = pyqtSignal(int)
class Worker(QRunnable):
def __init__(self, fn: Callable[[], str]) -> None:
super(Worker, self).__init__()
self.fn:Callable[[], str] = fn
self.signals: WorkerSignal = WorkerSignal()
@pyqtSlot()
def run(self) -> None: # <====================== this line
try:
result: str = self.fn()
except Exception:
traceback.print_exc()
exctype, value = sys.exc_info()[:2]
self.signals.error.emit((exctype, value, traceback.format_exc()))
else:
self.signals.result.emit(result)
finally:
self.signals.finished.emit()
$ mypy /tmp/tmp.py
/tmp/tmp.py:22: error: Signature of "run" incompatible with supertype "QRunnable" [override]
/tmp/tmp.py:22: note: Superclass:
/tmp/tmp.py:22: note: def run(self) -> None
/tmp/tmp.py:22: note: Subclass:
/tmp/tmp.py:22: note: str | None
Found 1 error in 1 file (checked 1 source file)
EDIT:
-
Is the following guess correct?
pyqtSlot()
takes function that returnstyping.Optional[str]
(i.e.str | None
). Perhaps its thesubclass
?QRunnable
's methodrun()
only returnNone
, Perhaps it's thesuperclass
?- In this case, correct question would be: How to use decorator, if
decorator's return
andfunction's return
are different? Would this be the correct question?
答案1
得分: 2
除了类型提示之外,你不应该在QRunnable方法中使用pyqtSlot。
pyqtSlot装饰器仅用于继承自QObject的类的方法,而QRunnable不是。我已经查阅了几个教程,它们采用了这种不好的做法,因为它并没有带来任何好处。
英文:
Other than the typehint you should not use pyqtSlot in a QRunnable method.
The pyqtSlot decorator is only used in methods of classes that inherit from QObject and QRunnable is not. I have reviewed several tutorials that resort to this bad practice since it does not bring any benefit.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论