[英]Why does sys.excepthook behave differently when wrapped?
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完成
這個答案 (我修改了該示例)顯示了如何安裝自定義異常掛鈎。 因此,讓我們取消上面示例中的代碼行注釋。 現在,它打印回溯,並且每次我們單擊該按鈕時都不會退出程序。
自定義函數只是舊函數的一個薄包裝。 為什么在引發異常時會導致不同的行為?
在PyQt4和舊版本的PyQt5(5.4或更舊版本)中,行為是在您描述的任何情況下都永遠不會退出應用程序。 在PyQt 5.5+中對此進行了更改(導致應用程序退出),但sys.excepthook
是沒有為sys.excepthook
明確指定異常處理程序。 這在文檔中有所提及,但在郵件列表中也有更詳細的說明。
文檔中的相關部分:
在很多情況下,都可以從C ++執行Python代碼。 C ++虛擬方法的Python重新實現可能是最常見的示例。 在以前的版本中,如果Python代碼引發異常,則PyQt將調用Python的PyErr_Print()函數,然后該函數將調用sys.excepthook()。 然后,默認的異常掛鈎將顯示異常以及對stderr的任何回溯。 這種行為有很多缺點:
- 應用程序不會終止,這意味着行為與在其他情況下引發異常時不同
- 開發人員或用戶(尤其是GUI應用程序)可能看不到寫入stderr的輸出,從而隱藏了該應用程序試圖報告潛在錯誤的事實。
PyQt v5.4中已棄用此行為。 在PyQt v5.5中,未處理的Python異常將導致調用Qt的qFatal()函數。 默認情況下,它將調用abort(),應用程序將終止。 請注意,應用程序安裝的異常掛鈎仍將優先。
來自郵件列表線程的相關部分:
我剛剛發現了PyQt 5.5的更改,其中未處理的異常導致調用qFatal()。 也許我錯過了一些重要的事情,但是我對為什么選擇這種行為感到困惑。 該文檔指出,舊行為的問題在於“應用程序不會終止,這意味着行為與在其他情況下引發異常時不同”。 我對此有兩個擔憂:
因為您當前正在運行C ++代碼時無法徹底退出Python。
- Python中未處理的異常不會導致程序終止。 它們只會導致sys.excepthook被調用。
如果您設置了一個,則與PyQt相同。
也許值得指出的是,最初的問題是pyqtgraph的創建者在pyqt郵件列表上提出的,並且河岸計算人員表示這種新行為不會消失。
如果要轉到源代碼,相關代碼位於pyqt5 / qpy / QtCore / qpycore_public_api.cpp( 此處是PyQt5的分叉版本)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.