为什么系统异常挂钩包装时表现不同?

2024-04-19 03:48:39 发布

您现在位置:Python中文网/ 问答频道 /正文

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_()

当我们点击按钮时

clicked

Process finished with exit code 1

This answer(我从中修改了示例)演示了如何安装自定义异常钩子。所以让我们取消注释上面例子中的代码行。现在它会打印回溯,并且不会在每次单击按钮时退出程序。在

自定义函数只是旧函数的一个简单包装。为什么在引发异常时会导致不同的行为?在


Tags: testimportself程序valuedefsysexception
1条回答
网友
1楼 · 发布于 2024-04-19 03:48:39

在PyQt4和PyQt5的旧版本(5.4或更高版本)中,行为是在您描述的任何情况下永远都不退出应用程序。这在PyQt 5.5+中进行了更改(以使应用程序退出),但前提是没有显式地为sys.excepthook指定异常处理程序。这在documentation中有所提及,但在mailing list中也有更详细的说明。在

文件中的相关部分:

There are a number of situations where Python code is executed from C++. Python reimplementations of C++ virtual methods is probably the most common example. In previous versions, if the Python code raised an exception then PyQt would call Python’s PyErr_Print() function which would then call sys.excepthook(). The default exception hook would then display the exception and any traceback to stderr. There are number of disadvantages to this behaviour:

  • the application does not terminate, meaning the behaviour is different to when exceptions are raised in other situations
  • the output written to stderr may not be seen by the developer or user (particularly if it is a GUI application) thereby hiding the fact that the application is trying to report a potential bug.

This behaviour was deprecated in PyQt v5.4. In PyQt v5.5 an unhandled Python exception will result in a call to Qt’s qFatal() function. By default this will call abort() and the application will terminate. Note that an application installed exception hook will still take precedence.

邮件列表线程中的相关部分:

I have just discovered the change to PyQt 5.5 in which unhandled exceptions result in a call to qFatal(). Perhaps I am missing something important, but I am a confused about why this behavior was chosen. The documentation states that the problem with the old behavior is that "the application does not terminate, meaning the behaviour is different to when exceptions are raised in other situations". I have two concerns about this reasoning:

因为当您当前正在运行时,不能干净地退出Python C++代码。在

  1. Unhandled exceptions in Python do not cause the program to terminate; they only cause sys.excepthook to be invoked.

PyQt也一样,如果你设置了一个。在

也许还值得指出的是,最初的问题是由pyqtgraph的创建者在pyqt邮件列表中提出的,riverbank computing的员工表示,这种新行为不会消失。在

如果要转到源代码,相关代码位于pyqt5/qpy/QtCore/qpycore_public_美国石油学会.cpp(PyQt5的分叉版本是here

相关问题 更多 >