豬行天下之Python基礎——6.1 異常與斷言

coder-pig發表於2019-04-08

內容簡述:

  • 1、異常
  • 2、斷言

1、異常

瞭解異常前,首先是區分「語法錯誤」與「執行時異常」,語法錯誤是連編譯器都過不了的錯誤,比如if語句後面漏掉了冒號(:),程式跑都跑不起來;執行錯誤則是程式跑起來後,因為程式的業務邏輯問題引起的程式崩潰,比如除以0。


① Python中的常見異常

Exception類 因為是 所有異常類的父類,又稱 萬能異常,可以捕獲任何異常!Python中常見的異常如下表所示:

異常 描述資訊
AssertionError 斷言語句失敗
AttributeError 嘗試訪問未知的物件屬性
IndexError 索引超出序列的範圍
keyError 字典中查詢一個不存在的Key
NameError 嘗試訪問一個不存在的變數
OSError 作業系統產生的異常,比如FileNotFoundError
SyntaxError Python語法錯誤
TypeError 不同型別間的無效操作
ZeroDivisionError 除數為0
IOError 輸入輸出錯誤
ValueError 函式傳參型別錯誤

② 異常捕獲

Python中為我們提供了兩組語句用於異常捕獲,try-expect-elsetry-finally。下面講解下六種常見的玩法:

「1. try捕獲了任何異常,直接丟給except後的程式碼塊處理」,程式碼示例如下:

try:
    result = 1 / 0
except:
    print("捕獲到異常了!")
複製程式碼

執行結果如下

捕獲到異常了!
複製程式碼

「2. 捕獲特定型別」,程式碼示例如下:

try:
    result = 1 / 0
except ZeroDivisionError:
    print("捕獲到除數為零的錯誤"
複製程式碼

執行結果如下

捕獲到除數為零的錯誤
複製程式碼

「3. 針對不同的異常設定多個except」,程式碼示例如下

執行結果如下

try:
    sum = 1 + '2'
    result = 1 / 0
except TypeError as reason:
    print("型別出錯:" + str(reason))
except ZeroDivisionError as reason:
    print("除數為0:" + str(reason))
複製程式碼

執行結果如下

型別出錯:unsupported operand type(s) for +: 'int' and 'str'
複製程式碼

「4. 對多個異常統一處理」,程式碼示例如下:

try:
    result = 1 / 0
    sum = 1 + '2'
except (TypeError, ZeroDivisionError) as reason:
    print(str(reason)) 
複製程式碼

執行結果如下

division by zero
複製程式碼

「5. 當沒有檢測到異常時才執行的程式碼塊,可以用else」,程式碼示例如下:

try:
    result = 4 / 2
except ZeroDivisionError as reason:
    print(str(reason))
else:
    print("沒有發生異常,輸出結果:%d" % result)
複製程式碼

執行結果如下

沒有發生異常,輸出結果:2
複製程式碼

6. 無論是否發生異常都會執行的一段程式碼塊」,程式碼示例如下:

try:
    result = 4 / 2
except ZeroDivisionError as reason:
    print(str(reason))
else:
    print("沒有發生異常,輸出結果:%d" % result)
finally:
    print("無論是否發生異常都會執行~")
複製程式碼

執行結果如下

沒有發生異常,輸出結果:2
無論是否發生異常都會執行。
複製程式碼

③ 異常丟擲

Python為我們提供的都是異常都是在特定條件下才會觸發的。而在一些特定的場景,某些操作可能會引起我們的業務異常,比如讓使用者輸入一串手機號碼,手機號碼由一串0-9的數字構成,而如果使用者輸入了其他字元,顯然是不合理的。我們可以通過正則對輸入的手機號碼進行校驗,如果是手機號碼就列印出來,不是的話則利用Python提供的raise關鍵字丟擲一個ValueError異常。程式碼示例如下:

import re

# 注:這段正則你只需要知道是用來匹配電話號碼的,正則在爬蟲那裡會詳細講解
phone_compile =re.compile(r'^(0|86|17951)?(13[0-9]|14[579]|15[0-35-9]|17[01678]|18[0-9])[0-9]{8}$')
number = input("請輸入一串手機號碼:")
if phone_compile.match(number) is not None:
    print("您輸入的手機號碼是:%s" % number)
else:
    raise ValueError
複製程式碼

執行結果如下

請輸入一串手機號碼:123456787
Traceback (most recent call last):
  File "F:/Project/Python/Book/Chapter 7/7_1_7.py", line 12in <module>
    raise ValueError
ValueError
複製程式碼

④ 自定義異常

上面通過raise關鍵字顯式的丟擲了一個內建的ValueError異常。如果程式裡除了這個號碼驗證還有郵箱驗證,我們又丟擲一個這樣的異常的話,會不利於異常的定位,異常是哪個地方引起的?對此,我們可以自定義異常,根據不同的錯誤丟擲對應的異常。我們自定義一個非手機號碼異常,程式碼示例如下:

# 自定義異常
class PhoneNumberException(Exception):
    def __init__(self, message):
        Exception.__init__(self)
        self.message = message

if __name__ == '__main__':
    phone_compile = re.compile(r'^(0|86|17951)?(13[0-9]|14[579]|15[0-35-9]|17[01678]|18[0-9])[0-9]{8}$')
    number = input("請輸入一串手機號碼:")
    if phone_compile.match(number) is not None:
        print("您輸入的手機號碼是:%s" % number)
    else:
        raise PhoneNumberException("非法的手機號碼!")
複製程式碼

執行結果如下

請輸入一串手機號碼:1234
Traceback (most recent call last):
  File "F:/Project/Python/Book/Chapter 7/7_1_8.py", line 19in <module>
    raise PhoneNumberException("非法的手機號碼!")
__main__.PhoneNumberException
複製程式碼

⑤ sys.exc_info()函式

除了前面介紹的獲取異常資訊的方式外,還可以通過sys模組裡的exc_info()函式 獲得,使用程式碼示例如下:

import sys

try:
    result = 1 / 0
except:
    tuple_exception = sys.exc_info()
# 輸出結果依次是:異常類,類示例,跟蹤記錄物件
for i in tuple_exception:
    print(i)
複製程式碼

執行結果如下

<class 'ZeroDivisionError'>
division by zero
<traceback object at 0x000001E079360288>
複製程式碼

2、斷言

assert關鍵字 後面的判斷條件為假的時候,程式自動崩潰並丟擲AssertionErro異常。一般在測試程式的時候才會用到:需要確保某個條件為真程式才能正常工作的時候使用

另外要和異常處理進行區分

異常處理」用於對程式發生異常情況的處理,以增加程式的健壯性和容錯性,而「斷言」則是用來檢查非法情況,用於幫助開發者快速定位問題位置

Python中關於斷言assert的玩法有兩種:

  • assert 判斷條件:如果判斷條件為false,就raise一個AssertionError
  • assert 判斷條件,異常描述:如果判斷條件為false,就raise一個帶描述資訊的AssertionError

程式碼示例如下

a, b = 12

# 第一種斷言用法
assert a > b
# 第二種斷言用法
assert (a > b), ("{a} 並不比 {b} 大'".format(a = a, b = b))
複製程式碼

執行結果如下

Traceback (most recent call last):
  File "F:/Project/Python/Book/Chapter 7/7_1_10.py", line 5in <module>
    assert a > b
AssertionError

Traceback (most recent call last):
  File "F:/Project/Python/Book/Chapter 7/7_1_10.py", line 6in <module>
    assert (a > b), ("{a} 並不比 {b} 大'".format(a = a, b = b))
AssertionError: 1 並不比 2 大'
複製程式碼

如果本文對你有所幫助,歡迎
留言,點贊,轉發
素質三連,謝謝?~


相關文章