2020年3月19日 星期四

Python 群益API Error in sys.excepthook

從一開始使用群益API時,就經常收到這個錯誤輸出。
Error in sys.excepthook:

Original exception was:
不以為意,因為運行不會受到任何影響。

關於這個錯誤,用GOOGLE搜尋會找到一篇文章,有做探討。

確實是直指出錯誤問題來源,但是並沒有解釋到底為什麼會出錯。

前幾天著手多進程,因此更瞭解當中的運作模式,這篇會更詳細講看法與解法。


首先要來到基本運作解釋:

 comtypes.client.GetEvents(),是可以把COM event傳到對應接收函式。

根據官方文件 COM events,comtypes.client.GetEvents() 會收到一個連接物件 <class 'comtypes.client._events._AdviseConnection'>,只要保持這個物件,就能保持狀態。

群益API範例沒有寫很多,後來看確實都有意義在的。

當登入報價之後,若是只有使用 time.sleep(),是會收不到回傳資料。

於是使用 pythoncom.PumpWaitingMessages(),好讓那些訊息有進到到主線程的時間。

訊息跟主線程並不在同一條線程上,因此可想有個子線程專門接收資料,到時候在送到對應的接收函式。

comtypes.client.GetEvents()的回傳值,就相當於一個這樣功能的子線程。

重新回到 Error in sys.excepthook 錯誤上,從網路上可以很容易查到解釋,就是主線程關掉了,但子線程卻還在運行。

這個物件的有無,對應著子線程運行有無,這可以解釋探討錯誤該文章的十八格狀態。

為什麼函式內用 comtypes.client.GetEvents() 就不會報錯,而在全域用就會報錯?函式結束時,函式內部變數也就被刪除,所以變數指定透過 comtypes.client.GetEvents() 得到的連接物件也就被刪除,連接子線程跟著中止。

在全域使用,在主線程結束時,自然是不會刪去這個連接物件。

要刪去這個連接物件,只需要使用 del 就能刪除了,是相當簡單的。

導致錯誤的關鍵點,就只是有沒有在主線程結束前刪掉這個連接物件。

其實不論在哪個域或類別中使用,也只需要在主線程結束之前,刪掉這個物件,或從類別中刪除這個屬性,就不會報錯了。