PyQt5 中未处理的异常

Unhandled exceptions in PyQt5

看看下面的MWE。

import sys

from PyQt5.QtWidgets import QMainWindow, QPushButton, QApplication

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.button = QPushButton('Bham!')
        self.setCentralWidget(self.button)
        self.button.clicked.connect(self.btnClicked)

    def btnClicked(self):
        print(sys.excepthook)
        raise Exception


#import traceback
#sys.excepthook = traceback.print_exception

if __name__ == '__main__':
    app = QApplication(sys.argv)
    mainWindow = MainWindow()
    mainWindow.show()
    app.exec_() 

我有很多问题。不知道是不是都相关(我猜是),如果不是请见谅。

  1. 当我从终端运行上面的代码时,一切正常。程序 运行s,如果我单击按钮,它会打印回溯并终止。如果我 运行 它在 IDE 中(我测试了 Spyder 和 PyCharm),则不会显示回溯。知道为什么吗? SO 上的其他帖子也提出了本质上相同的问题, and 。请不要将其标记为其中任何一个的副本;请继续阅读。

  2. 通过添加注释行,回溯再次正确显示。然而,它们也有令人讨厌的副作用,即应用程序不再因未处理的异常而终止!我不知道为什么会这样,因为 AFAIK excepthook 打印 回溯,它无法阻止程序 退出 。此刻召唤已来不及救援

  3. 此外,我不明白 Qt 如何在这里发挥作用,因为未在插槽内抛出的异常仍会像我预期的那样使应用程序崩溃。不管我是否更改 excepthook,PyQt 似乎也不会覆盖它(至少 print 似乎是这样建议的)。

仅供参考,我将 Python 3.5 与 PyQt 5.6 一起使用,并且我知道 PyQt 5.5 中引入的异常处理的变化。如果这些确实是导致上述行为的原因,我很乐意听到一些更详细的解释。

当 Qt 槽内发生异常时,是 C++ 调用了您的 Python 代码。由于 Qt/C++ 对 Python 异常一无所知,因此您只有两种可能性:

  • 打印异常和 return C++ 的一些默认值(如 0、"" 或 NULL),可能会产生意想不到的副作用。这就是 PyQt < 5.5 所做的。
  • 打印异常然后调用qFatal() or abort(),导致应用程序在 C++ 中立即退出。这就是 PyQt >= 5.5 所做的,除非你有一个自定义的 excepthook 集。

Python 仍然没有终止的原因可能是它不能终止,因为它在某些 C++ 代码中。你的 IDE 没有显示堆栈的原因可能是因为它没有正确处理 abort() - 我建议为此打开一个针对 IDE 的错误。