###### tags: `python` # 除錯與異常處理 ## 例外 * 語法錯誤(syntax error):不符合python程式撰寫規則 * 沒有縮排 * 拼錯python指令、參數格式不符合函數要求 * 不管如何執行時一定會發生錯誤 * 比較容易除錯 * 執行期間錯誤(runtime error):執行程式時發生的錯誤 * 使用者輸入預期以外的資料 * 系統軟硬體出現異常 * 執行時可能正常也可能發生錯誤,端看使用者輸入資料或操作而定 * 邏輯錯誤(logic error):沒有任何錯誤訊息,但程式邏輯不符合商業邏輯 * 使用者登入後可瀏覽其他使用者的檔案資訊 --- 當錯誤發生時程式就被中斷並產生讓使用者害怕的錯誤畫面 ### 範例1 ```python= x = int(input("input first num: ")) y = int(input("input second num: ")) z = x / y print(z) ``` 透過try...except補抓錯誤狀態,導向使用者理解的錯誤訊息 並讓程式仍然可以正常繼續運作 ### 範例2 ```python= while True: try: x = int(input("input first num: ")) y = int(input("input second num: ")) z = x / y except: print("error") print(z) ``` 發生不同錯誤顯示不同錯誤訊息 讓錯誤訊息更加明確具體 ### 範例3 ```python= while True: try: x = int(input("input first num: ")) y = int(input("input second num: ")) z = x / y print(z) except ZeroDivisionError: print("y can't be zero") except ValueError: print("please input number") except: print("error") ``` 顯示python預設錯誤訊息 ### 範例4 ```python= while True: try: x = int(input("input first num: ")) y = int(input("input second num: ")) z = x / y print(z) except ZeroDivisionError: print("y can't be zero") except Exception as e: print(e) ``` **else**: 當沒有發生任何錯誤時執行 **finally**: 不管有沒有發生錯誤都要執行這一行 ### 範例5 ```python= count = 0 while True: try: x = int(input("input first num: ")) y = int(input("input second num: ")) z = x / y except Exception as e: print(e) else: print(z) finally: count += 1 print("count: ", count) ``` 在開發函數、物件、套件時,我們會在開發者不正確使用時故意產生錯誤 提醒開發者錯誤發生在哪裡 避免開發者最後才知道不正確 而需要整個程式碼下去一個一個除錯 浪費大量成本 ### 範例6 ```python= try: x = int(input('num: ')) if x >= 100: raise NameError("數字不可大於100") elif x < 0: raise NameError("數字不可小於0") except Exception as e: print(e) ``` --- ## 日誌(log) * 可控制除錯訊息顯示或不顯示 * 方便將除錯資訊寫入檔案 ### 日誌等級 由高到低 * **危急(critical)**:顯示發生系統或電腦嚴重當機時的資訊 * **錯誤(error)**:顯示發生錯誤時的資訊 * **警告(warning)**:顯示可能會發生錯誤時的資訊 * **資訊(info)**:顯示一般事件發生時的資訊,例如執行某函數或觸發某事件 * **除錯(debug)**:顯示關鍵變數變化的資訊 ### 範例7 各位可以試者修改第三行,將logging.basicConfig(level=**logging.DEBUG**) 改成logging.basicConfig(level=**logging.ERROR**) 看看執行結果會有什麼變化 ```python= import logging logging.basicConfig(level=logging.DEBUG) logging.debug('DEBUG level message') logging.info('INFO level message') logging.warning('WARNING level message') logging.error('ERROR level message') logging.critical('CRITICAL level message') ``` ### 範例8 ```python= import logging logging.basicConfig(level=logging.ERROR) while True: try: x = int(input("input first num: ")) y = int(input("input second num: ")) logging.debug("x: "+ str(x)) logging.debug("y: "+ str(y)) z = x / y print(z) except ZeroDivisionError: logging.error("y can't be zero") except Exception as e: logging.error(e) ``` ### 範例9 透過logging.info顯示進入、離開函數showMsg訊息 ```python= #-*- coding:utf-8 -*- import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s: %(message)s') def showMsg(): logging.info('執行showMsg函數') print("hello") logging.info('結束showMsg函數') showMsg() ``` ### 範例10 試者註解掉37~42行看看有什麼變化 ```python= import logging logging.basicConfig(level=logging.DEBUG, format='[%(asctime)s] %(levelname)s: %(message)s') class Animal: logging.info('run class Animal') def __init__(self, head, hand, foot): logging.info('run class Animal: __init__()') self.head = head self.hand = hand self.foot = foot def run(self): logging.info('run class Animal: run()') return '使用身體快速移動' class Bird(Animal): logging.info('run class Bird') def __init__(self, head, wing, foot): logging.info('run class Bird: __init__()') self.head = head self.wing = wing self.foot = foot def run(self): logging.info('run class Bird: run()') return '使用雙腳奔跑' def fly(self): logging.info('run class Bird: fly()') return '使用翅膀飛翔' if __name__ == '__main__': animal = Animal(1, 0, 4) print(animal.run()) bird = Bird(1, 2, 2) print(bird.run()) print(bird.fly()) ``` ---- ## 格式化除錯訊息 ### 範例11 ```python= #-*- coding:utf-8 -*- import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s: %(message)s') logging.debug('除錯訊息') logging.info('資訊訊息') logging.warning('警告訊息') logging.error('錯誤訊息') logging.critical('危急訊息') ``` ### 輸出除錯訊息到檔案 ### 範例12 ```python= import logging logging.basicConfig(level=logging.DEBUG, filename='debug.log', format='%(asctime)s - %(levelname)s: %(message)s') while True: try: x = int(input("input first num: ")) y = int(input("input second num: ")) logging.debug("x: "+ str(x)) logging.debug("y: "+ str(y)) z = x / y print(z) except ZeroDivisionError: logging.error("y can't be zero") except Exception as e: logging.error(e) ```