Python學習筆記-異常處理

異常處理

Python Errors and Exceptions 官方文檔html

  • 引起異常:
    • 語法: 使用raise 關鍵字, raise either an exception instance or an exception class (a class that derives from Exception).
      raise NameError('wrong name')
      樣例輸出:
      Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: wrong name
    • 常見的內置異常類:
      • Exception:
      • AttributeError: 引用屬性或給它賦值失敗
      • IndexError: 使用了序列中不存在的索引時引起, 爲Lookup Error子類
      • KeyError: 使用映射中不存在的索引時引起, 爲Lookup Error子類
      • NameError: 找不到對應名稱(變量)時引起
      • TypeError: 將內置操做或函數用於類型不正確的對象時引起
      • ValueError: 將內置操做或函數用於這樣的對象時引起, 類型正確可是包含的值不對
  • 建立異常(User-defined Exception):
    • 語法: 建立一個異常類, 必需要保證直接或間接的繼承Exception父類 Exceptions should typically be derived from the Exception class, either directly or indirectly.
    • 樣例: class MyError(Exception): pass
    • 細節:
      • 類儘可能簡單, 只須要定義一些關於Error的屬性, 方便傳給handler進行異常處理
      • 若是在一個module當中須要定義多個Exception Class, 先定義一個BaseError Class, 讓其餘的subclass Error來繼承該BaseError Class: When creating a module that can raise several distinct errors, a common practice is to create a base class for exceptions defined by that module, and subclass that to create specific exception classes for different error conditions:
      • 異常的定義應當以'Error'結尾,這樣符合內置異常的命名規範
  • 處理異常
    • 語法: try/except 關鍵字
    • 樣例: try 後面能夠接 0個 exception, 1個 exception, 多個exception
      • 0個exception(危險的操做,儘可能避免) 表示一次打包處理全部的異常
      • 1個異常: 只有異常名稱對應於try當中拋出的異常時纔會被執行
      • 多個異常:
        • 樣例: exception (NameError, TrancisionError, ValueError): pass 三個當中任意一個知足時,都會catch並處理
        • 細節: 語法當中的( )不能省略, except RuntimeError, TypeError is not equivalent to except (RuntimeError, TypeError): but to except RuntimeError as TypeError
    • try關鍵字的執行流程:
      The try statement works as follows.
      First, the try clause (the statement(s) between the try and except keywords) is executed.
      If no exception occurs, the except clause is skipped and execution of the try statement is finished.
      If an exception occurs during the execution of the try clause, the rest of the clause is skipped. Then if its type matches the exception named after the except keyword, the except clause is executed, and then execution continues after the try statement.
      If an exception occurs which does not match the exception named in the except clause, it is passed on to outer try statements; if no handler is found, it is an unhandled exception and execution stops with a message as shown above.python

    • 對except子句當中訪問異常對象自己的操做:
      • 爲exception instance 命名, 以便於在異常的內部進行調用
      • 爲異常對象添加attribute: we can add arguments to the exception. The except clause may specify a variable after the exception name (or tuple). The variable is bound to an exception instance with the arguments stored in instance.args. 必需要對instance命名, 而後才能在以後面進行調用
    • 異常當中的else語句: 執行沒有異常時須要作的事情
      The try … except statement has an optional else clause, which, when present, must follow all except clauses. It is useful for code that must be executed if the try clause does not raise an exception. For example:json

try:
    <statements>  # Run this main action first
except <name1>:
    <exc1>           # 當 try中發生了 name1 的異常時運行exc1
except <name2>:
    <exc2>           # 當 try中發生了 name2 的異常時運行exc2
except (<name3>, <name4>:
    <exc3>           # 當 try中發生了 name3 OR name4 的異常時運行exc3
else: 
    <exc4>           # 當代碼沒有異常時運行exc4
finally: 
    <final>            #無論代碼有沒有異常都會執行final, 一般用來作一些清理工做
  • 細節: 異常處理當中的幾點基本原則:
    • 注意異常的粒度,try當中不該當放入過多的代碼,過多的代碼會使得異常的定位難以定位, 儘可能只在可能拋出異常的語句塊前面放入try語句
    • 謹慎使用單獨的except語句處理全部異常, 最好可以定位具體的異常。由於不加具體類型的except可能會掩蓋真實的錯誤
    • 樣例:
    import sys
    try: 
        print a
        b = 0
        print a / b
    except:
        sys.exit("ZeroDivisionError:Can not division zero")
    程序打印"ZeroDivisionError: Can not division zero", 可是這不是真正的錯誤緣由, 真正的錯誤緣由是a 在使用以前沒有進行定義
    • 注意異常的捕獲順序: 小 -> 大 由於異常的捕獲是順序執行的, 小的在前能夠直接精肯定位異常, 而大的在前若是鎖定不了異常的話, 還要再次執行小的,畫蛇添足,大小的劃分根據內建異常的繼承結構來肯定。原則是若是異常可以在被捕獲的位置處理就應當及時的進行處理, 不能處理也應當以合適的方式向上層拋出。向上層傳遞時使用raise關鍵字便可。大類錯誤能夠捕捉子類中的錯誤

【25/91建議】避免finally 可能發生的陷阱:dom

  • 陷阱: 異常屏蔽 OR 設計好的return語句被屏蔽
    • 當finally 語句之中出現了returnbreak語句時, 臨時保存的異常 和 try當中本來被設計好的return語句將被丟失
    • 樣例:
    def ReturnTest(a):
        try:
            if a <= 0:
                raise ValueError("data can not be negative")
            else:
                return a
        except ValueError as e:
            print e
        finally:
            print("The End!")
            return -1
    
        print ReturnTest(0) # 輸出"The End!" "-1" 
        print ReturnTest(1) # 輸出"The End!" "-1"  出現問題

finally 當中的return在try 中的else 語句以前執行, 因此會直接運行 finally 當中的return -1 而不是try 當中的 return aide

  • 異常處理模板:
    • try/finally結構: 若是既要將異常向上傳播, 又要在異常發生時進行清理工做
    • 樣例: read方法拋出的異常會向上傳播給調用方, 而finally代碼塊中的handle.close方法則必定能被執行。open方法必須放在try語句外, 這樣若是打開文件時發生異常會跳過finally塊
    handle = open('/tmp/random_data.txt') # May raise IOError
    try:
        data = handle.read() # May raise UnicodeDecode Error
    finally:
        handle.close() # Always runs after try
    • try/except/else結構: 清晰描述哪些異常由本身的代碼處理、哪些異常會傳給上一級。若是try代碼中沒有發生異常, 那麼就執行else語句, 有了這種else 語句, 咱們就能夠儘可能縮減try中的代碼量。
    • 樣例:
    def load_json_key(data, key):
        try:
            result_dict = json.loads(data) # 嘗試讀取一個JSON文件
        except ValueError as e:
            raise KeyError from e  # 若是代碼不是有效的JSON格式, 會產生ValueError
        else:
            return result_dict[key] # 代碼是有效的JSOn格式, 進行處理
    • 全套四合一 try/except/else/finally結構
    • 樣例:
    def divide_json(path):
    handle = open(path, 'r+')
    try:
        data = handle.read()
        op = json.loads(data)
        value = (
            op['numerator'] /
            op['denominator']) # May raise ZeroDivisionError
    except ZeroDivisionError as e:
        return UNDEFINED
    else:
        op['result'] = value
        result = json.dumps(op)
        handle.seek(0)
        handle.write(result) # May raise IOError
        return value
    finally:
        handle.close() # Always runs
  • 使用內置的logging模塊 來記錄exception信息
  • 樣例:
def main():
    try:
        bar('0')
    except Exception as e:
        logging.exception(e)
相關文章
相關標籤/搜索