1. 程式人生 > 實用技巧 >Python學習筆記7:錯誤和異常

Python學習筆記7:錯誤和異常

我們在程式編寫和執行過程中,總會遇到各種各樣的錯誤。
1.有的錯誤是編寫程式時語法錯誤。比如少了:冒號,縮排不合理等等。
2.有的錯誤是程式編寫有問題造成的,比如本來應該輸出整數結果輸出了字串,這種錯誤我們通常稱之為bug,bug是必須修復的。
3.有的錯誤是使用者輸入造成的,比如讓使用者輸入email地址,結果得到一個空字串,這種錯誤可以通過檢查使用者輸入來做相應的處理。
4.還有一類錯誤是完全無法在程式執行過程中預測的,比如寫入檔案的時候,磁碟滿了,寫不進去了,或者從網路抓取資料,網路突然斷掉了。這類錯誤也稱為異常,在程式中通常是必須處理的,否則,程式會因為各種問題終止並退出。

所以程式需要一種處理錯誤與異常的機制,而Python的錯誤異常處理能力是很強大的,它有很多內建異常,可向使用者準確反饋出錯資訊。
1.語法錯誤

>>> if True print('hello world!') # 少寫了:冒號
SyntaxError: invalid syntax
>>> 

2.Python內建異常
異常即是一個事件,該事件會在程式執行過程中發生,影響了程式的正常執行。
一般情況下,在Python無法正常處理程式時就會發生一個異常。
異常是Python物件,表示一個錯誤。
當Python指令碼發生異常時我們需要捕獲處理它,否則程式會終止執行。

在Python中,異常也是物件,可對它進行操作。BaseException是所有內建異常的基類,但使用者定義的類並不直接繼承BaseException,所有的異常類都是從Exception繼承,且都在exceptions模組中定義。
Python自動將所有異常名稱放在內建名稱空間中,所以程式不必匯入exceptions模組即可使用異常。一旦引發而且沒有捕捉SystemExit異常,程式執行就會終止。如果互動式會話遇到一個未被捕捉的SystemExit異常,會話就會終止。

BaseException  # 所有異常的基類
 +-- SystemExit  # 直譯器請求退出
 +-- KeyboardInterrupt  # 使用者中斷執行(通常是輸入^C)
 +-- GeneratorExit  # 生成器(generator)發生異常來通知退出
 +-- Exception  # 常規異常的基類
      +-- StopIteration  # 迭代器沒有更多的值
      +-- StopAsyncIteration  # 必須通過非同步迭代器物件的__anext__()方法引發以停止迭代
      +-- ArithmeticError  # 各種算術錯誤引發的內建異常的基類
      |    +-- FloatingPointError  # 浮點計算錯誤
      |    +-- OverflowError  # 數值運算結果太大無法表示
      |    +-- ZeroDivisionError  # 除(或取模)零 (所有資料型別)
      +-- AssertionError  # 當assert語句失敗時引發
      +-- AttributeError  # 屬性引用或賦值失敗
      +-- BufferError  # 無法執行與緩衝區相關的操作時引發
      +-- EOFError  # 當input()函式在沒有讀取任何資料的情況下達到檔案結束條件(EOF)時引發
      +-- ImportError  # 匯入模組/物件失敗
      |    +-- ModuleNotFoundError  # 無法找到模組或在在sys.modules中找到None
      +-- LookupError  # 對映或序列上使用的鍵或索引無效時引發的異常的基類
      |    +-- IndexError  # 序列中沒有此索引(index)
      |    +-- KeyError  # 對映中沒有這個鍵
      +-- MemoryError  # 記憶體溢位錯誤(對於Python 直譯器不是致命的)
      +-- NameError  # 未宣告/初始化物件 (沒有屬性)
      |    +-- UnboundLocalError  # 訪問未初始化的本地變數
      +-- OSError  # 作業系統錯誤,EnvironmentError,IOError,WindowsError,socket.error,select.error和mmap.error已合併到OSError中,建構函式可能返回子類
      |    +-- BlockingIOError  # 操作將阻塞物件(e.g. socket)設定為非阻塞操作
      |    +-- ChildProcessError  # 在子程序上的操作失敗
      |    +-- ConnectionError  # 與連線相關的異常的基類
      |    |    +-- BrokenPipeError  # 另一端關閉時嘗試寫入管道或試圖在已關閉寫入的套接字上寫入
      |    |    +-- ConnectionAbortedError  # 連線嘗試被對等方中止
      |    |    +-- ConnectionRefusedError  # 連線嘗試被對等方拒絕
      |    |    +-- ConnectionResetError    # 連線由對等方重置
      |    +-- FileExistsError  # 建立已存在的檔案或目錄
      |    +-- FileNotFoundError  # 請求不存在的檔案或目錄
      |    +-- InterruptedError  # 系統呼叫被輸入訊號中斷
      |    +-- IsADirectoryError  # 在目錄上請求檔案操作(例如 os.remove())
      |    +-- NotADirectoryError  # 在不是目錄的事物上請求目錄操作(例如 os.listdir())
      |    +-- PermissionError  # 嘗試在沒有足夠訪問許可權的情況下執行操作
      |    +-- ProcessLookupError  # 給定程序不存在
      |    +-- TimeoutError  # 系統函式在系統級別超時
      +-- ReferenceError  # weakref.proxy()函式建立的弱引用試圖訪問已經垃圾回收了的物件
      +-- RuntimeError  # 在檢測到不屬於任何其他類別的錯誤時觸發
      |    +-- NotImplementedError  # 在使用者定義的基類中,抽象方法要求派生類重寫該方法或者正在開發的類指示仍然需要新增實際實現
      |    +-- RecursionError  # 直譯器檢測到超出最大遞迴深度
      +-- SyntaxError  # Python 語法錯誤
      |    +-- IndentationError  # 縮排錯誤
      |         +-- TabError  # Tab和空格混用
      +-- SystemError  # 直譯器發現內部錯誤
      +-- TypeError  # 操作或函式應用於不適當型別的物件
      +-- ValueError  # 操作或函式接收到具有正確型別但值不合適的引數
      |    +-- UnicodeError  # 發生與Unicode相關的編碼或解碼錯誤
      |         +-- UnicodeDecodeError  # Unicode解碼錯誤
      |         +-- UnicodeEncodeError  # Unicode編碼錯誤
      |         +-- UnicodeTranslateError  # Unicode轉碼錯誤
      +-- Warning  # 警告的基類
           +-- DeprecationWarning  # 有關已棄用功能的警告的基類
           +-- PendingDeprecationWarning  # 有關不推薦使用功能的警告的基類
           +-- RuntimeWarning  # 有關可疑的執行時行為的警告的基類
           +-- SyntaxWarning  # 關於可疑語法警告的基類
           +-- UserWarning  # 使用者程式碼生成警告的基類
           +-- FutureWarning  # 有關已棄用功能的警告的基類
           +-- ImportWarning  # 關於模組匯入時可能出錯的警告的基類
           +-- UnicodeWarning  # 與Unicode相關的警告的基類
           +-- BytesWarning  # 與bytes和bytearray相關的警告的基類
           +-- ResourceWarning  # 與資源使用相關的警告的基類。被預設警告過濾器忽略。

異常處理

try/except

try:
    try_suite        #要處理的邏輯程式碼
except Exception[e]: #Exception是要處理的異常類,e用於儲存出現異常的型別
    exception_block  #處理捕獲異常之後的邏輯

#try用來捕獲try_suite中的操作,並且將錯誤交給except處理。
#except用來處理異常,如果處理異常和設定異常一致,使用exception_block處理異常,不一致的話就會被直譯器處理,如果有e設定時,這個錯誤就會儲存在e中。

如下程式碼:

try:
    a
except NameError as e:
    print('Error:',e)

print 'over'

#輸出結果
Error: name 'a' is not defined
over

如下異常可以捕獲,因為是執行時錯誤:

try:
    undef
except:
    print("catch an except")

不能捕獲異常,因為是語法錯誤,執行前錯誤(因為程式碼執行前直譯器會對語法進行檢查,有錯誤就丟擲,這時程式碼還沒有真正執行)

>>> try:
    if undef
except:
    print("catch an except")
    
SyntaxError: invalid syntax
>>> 

如下異常可以捕獲,可以指定處理某種異常(NameError):

>>> try:
	undef
except NameError as e:
	print('catch an except {}'.format(e))

catch an except name 'undef' is not defined
>>> 

如下程式碼:
輸出結果,報錯,錯誤是NameError: name 'undef' is not defined
不能捕獲異常,因為設定IOError,不會處理NameError,會把異常拋給直譯器進行處理

>>> try:
	undef
except IOError as e:
	print('catch an except {}'.format(e))

Traceback (most recent call last):
  File "<pyshell#41>", line 2, in <module>
    undef
NameError: name 'undef' is not defined
>>> 

try/except...else
else 子句將在 try 子句沒有發生任何異常的時候執行。

>>> try:
	print(name)
except Exception as e: #所有的異常都處理
	print('error come: {}'.format(e))
else:
	print('no error') #try 子句發生任何異常,不執行這裡

error come: name 'name' is not defined

>>> try:
	name='James'
	print(name)
except Exception as e:
	print('error come: {}'.format(e))
else:
	print('no error') #try 子句沒有發生任何異常,執行這裡

James
no error
>>> 

try-finally
finally 語句無論是否發生異常都將執行最後的程式碼。

>>> try:
	print(name)
except Exception as e:
	print('error come: {}'.format(e))
else:
	print('no error')
finally:
	print('finally come here') #無論是否發生異常都將執行最後的程式碼

error come: name 'name' is not defined
finally come here
>>> 

丟擲異常
Python 使用 raise 語句丟擲一個指定的異常。

raise語法格式如下:

raise [Exception [, args [, traceback]]]

以下例項如果 x 大於 5 就觸發異常:

>>> x=6
>>> if x>5:
	raise Exception('x cannot large than 5, x={}'.format(x))

Traceback (most recent call last):
  File "<pyshell#4>", line 2, in <module>
    raise Exception('x cannot large than 5, x={}'.format(x))
Exception: x cannot large than 5, x=6
>>>