Qt静默捕获Python回调中的异常,并使用错误代码退出程序。这可以通过一个简短的例子来证明:
import sys
from PyQt5 import QtWidgets
# _excepthook = sys.excepthook
# def exception_hook(exctype, value, traceback):
# _excepthook(exctype, value, traceback)
# sys.excepthook = exception_hook
class Test(QtWidgets.QPushButton):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent)
self.setText("hello")
self.clicked.connect(self.buttonClicked)
def buttonClicked(self):
print("clicked")
raise Exception("wow")
app = QtWidgets.QApplication(sys.argv)
t = Test()
t.show()
app.exec_()
点击按钮后,我们
点击
使用退出代码1完成处理
This answer(我修改了该示例)演示了如何安装自定义异常挂钩。因此,请在上面的示例中取消注释代码行。现在它打印回溯,并且每次单击按钮时都不会退出程序。
自定义函数只是旧函数的一个薄包装器。为什么在引发异常时会导致不同的行为?
答案 0 :(得分:4)
在PyQt4和旧版本的PyQt5(5.4或更早版本)中,行为是在您描述的任何情况下永远不会退出应用程序。这在PyQt 5.5+中已更改(导致应用程序退出),但前提是没有为sys.excepthook
显式指定的异常处理程序。这在[{3}}中有所提及,但在documentation上有更详细的说明。
文件中的相关部分:
在许多情况下执行Python代码 C ++。 Python重新实现C ++虚拟方法可能就是这样 最常见的例子。在以前的版本中,如果引发了Python代码 PyQt会调用Python的PyErr_Print()函数 然后调用sys.excepthook()。默认的异常挂钩 然后会显示异常和任何追溯到stderr。那里 这种行为有多少缺点:
- 应用程序不会终止,这意味着行为不同 当在其他情况下引发例外时
- 开发人员或用户可能看不到写入stderr的输出(特别是如果它 是一个GUI应用程序)从而隐藏了应用程序的事实 试图报告潜在的错误。
此行为已被弃用 PyQt v5.4。在PyQt v5.5中,未处理的Python异常将导致a 调用Qt的qFatal()函数。默认情况下,这将调用abort()和 申请将终止。请注意,已安装应用程序 异常钩子仍然优先。
邮件列表主题中的相关部分:
我刚刚发现对PyQt 5.5的更改,其中未处理的异常 导致调用qFatal()。也许我错过了一些重要的东西,但是 我很困惑为什么选择这种行为。文档 指出旧行为的问题在于应用程序的问题 不终止,意味着行为与异常时不同 在其他情况下提出"。我对这个推理有两个担忧:
因为当你正在运行时,你无法干净地退出Python C ++代码。
- Python中未处理的异常不会导致程序终止; 它们只会导致调用sys.excepthook。
醇>与PyQt相同,如果你设置了一个。
也许值得指出的是,pyqtgraph的创建者在pyqt邮件列表上提出了原始问题,并且河岸计算的工作人员说这种新行为并没有消失。
如果你想转到源代码,相关代码位于pyqt5 / qpy / QtCore / qpycore_public_api.cpp(PyQt5的分叉版本为mailing list)