PyQt5 中未处理的异常

Posted

技术标签:

【中文标题】PyQt5 中未处理的异常【英文标题】:Unhandled exceptions in PyQt5 【发布时间】:2017-09-24 07:06:02 【问题描述】:

看看下面的 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_() 

我有很多问题。我不知道它们是否都相关(我想是的),如果不是,请原谅我。

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

    通过添加注释行,回溯再次正确显示。但是,它们也有令人讨厌的副作用,即应用程序不再因未处理的异常而终止!我不知道为什么会发生这种情况,因为 AFAIK excepthook打印回溯,它不能阻止程序退出。在调用的那一刻,抢救已经来不及了。

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

仅供参考,我正在使用 Python 3.5 和 PyQt 5.6,并且我知道 PyQt 5.5 中引入的异常处理的变化。如果这些确实是上述行为的原因,我会很高兴听到一些更详细的解释。

【问题讨论】:

【参考方案1】:

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

打印异常并向 C++ 返回一些默认值(如 0、“”或 NULL),可能会产生意想不到的副作用。这就是 PyQt 打印异常,然后调用qFatal() 或abort(),导致应用程序立即退出C++。这就是 PyQt >= 5.5 所做的,除非您设置了自定义的异常钩子。

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

【讨论】:

非常感谢您的回答。这对我来说很有意义。我将不得不考虑它并多玩一点。如果我有其他问题,我会回复您,如果没有,请接受答案。现在就给 +1 吧!

以上是关于PyQt5 中未处理的异常的主要内容,如果未能解决你的问题,请参考以下文章

在多线程 C++11 程序中未处理异常时会发生啥?

在多线程 C++11 程序中未处理异常时会发生啥?

我可以让 Visual Studio 停止任务代码中未处理的异常吗?

vc++ 中未处理的异常 (msvcp100d.dll)

对象识别 OpenCV 中未处理的异常

为啥后台线程中未处理的异常不会使应用程序域崩溃?