2016-07-19 35 views
1

我爲使用Tkinter接收用戶輸入的其他人開發了幾個Python程序。爲了保持簡單和用戶友好,命令行或python控制檯永遠不會出現(即使用.pyw文件),所以我正在研究使用日誌庫將錯誤文本寫入文件發生異常。但是,我很難找到實際的異常。例如:使用Python在Tkinter中保存異常

我們寫的,這將導致錯誤的函數:

def cause_an_error(): 
    a = 3/0 

現在我們嘗試登錄正常誤差:

import logging 
logging.basicConfig(filename='errors.log', level=logging.ERROR) 

try: 
    cause_an_error() 
except: 
    logging.exception('simple-exception') 

正如預期的那樣,程序中的錯誤,並記錄寫入error.log錯誤。控制檯中不顯示任何內容。然而,有一個不同的結果,當我們實現一個Tkinter的接口,像這樣:

import logging 
import Tkinter 
logging.basicConfig(filename='errors.log', level=logging.ERROR) 

try: 
    root = Tkinter.Tk() 
    Tkinter.Button(root, text='Test', command=cause_an_error).pack() 
    root.mainloop() 
except: 
    logging.exception('simple-exception') 

在這種情況下,在Tkinter的窗口中按下此按鈕會造成錯誤。然而,這一次,沒有數據被寫入到文件,並顯示在控制檯以下錯誤:

Exception in Tkinter callback 
Traceback (most recent call last): 
    File "C:\Python27\lib\lib-tk\Tkinter.py", line 1536, in __call__ 
    return self.func(*args) 
    File "C:/Users/samk/Documents/GitHub/sandbox/sandbox2.pyw", line 8, in cause_an_error 
    a = 3/0 
ZeroDivisionError: integer division or modulo by zero 

是否有不同的方式來捕捉和記錄這個錯誤?

+0

Tkinter的運行在自己的線程,並root.mainloop'後'在於這一切只後執行你關上窗戶。還要注意'cause_an_error'只在你點擊按鈕時執行,但是首先執行'root.mainloop'。可能發生的情況是,這個例外沒有被捕獲,因爲它被扔進了一個不同的「環境」......我希望有人提出一個更詳細和技術性的答案。 – nbro

+0

有趣。現在你提到它了,'raise'命令也無法檢索錯誤,所以它肯定會被拋入不同的環境中。有沒有辦法可以修改Tkinter的錯誤處理,以便在導入後包含日誌記錄? –

+0

你可以直接在函數中捕獲異常... – nbro

回答

2

它沒有很好的記錄,但tkinter調用一個方法來處理回調的結果。您可以編寫自己的方法,通過在根窗口上設置屬性report_callback_exception來執行任何您想要的操作。

例如:

import tkinter as tk 

def handle_exception(exception, value, traceback): 
    print("Caught exception:", exception) 

def raise_error(): 
    raise Exception("Sad trombone!") 

root = tk.Tk() 
# setup custom exception handling 
root.report_callback_exception=handle_exception 

# create button that causes exception 
b = tk.Button(root, text="Generate Exception", command=raise_error) 
b.pack(padx=20, pady=20) 

root.mainloop() 

參考:

+0

完美,謝謝! :)有沒有辦法檢索產生異常的行號或函數? –

+1

@SamKrygsheld:看看'traceback'參數。 –

+0

啊,是的,謝謝。對於將來可能會看到這一點的任何人,我曾假設傳入的回溯是一個字符串,但它實際上是一個回溯對象。使用traceback.tb_lineno將允許您訪問行號。 –