Python——異常(內置異常以及應用場景)

"""
什麼是異常:
一、異常指出了咱們的程序有錯誤
二、有些異常也會在一些合法的狀況下發生,好比用戶名密碼錯誤,銀行卡號不存在
三、內置異常的名字都是以Error結尾:ZeroDivisionError,IndexError,SyntaxError
四、全部異常類都是繼承於Exception,(擴展BaseException)
五、當一個異常發生的時候,會當即中止程序的執行,除非正確的處理這個異常
六、異常是一個對象,而且能夠繼承(經過繼承Exception類來實現本身的異常)
"""

# print "hello"
#拋出異常信息:SyntaxError: Missing parentheses in call to 'print'. Did you mean print("hello")?
#產生的SyntaxError異常,這就是異常,語法錯誤的異常

#x = 5 / 0
#print(x)
#拋出ZeroDivisionError異常,信息:ZeroDivisionError: division by zero,說是不能被除

# lst = [1,2,3]
# print(lst[3])
#拋出異常:IndexError: list index out of range 說是索引錯誤

#經過內置的TypeError和ValueError類來構造異常對象,下面的例子擴展了內置的list,並重寫了該內之類的append方法
class MyList(list): #繼承內置的list類
    def append(self, integer):
        if not isinstance(integer, int): #若是不是整數則拋出異常
            raise TypeError("Not an integer")
        if integer % 2:
            raise ValueError("Can not be divisible") #不能整除時則拋出異常
        super().append(integer) #調用父類的append方法
# mylist = MyList()
# #mylist.append(12.45) #引起TypeError異常
# #mylist.append(87) #引起ValueError異常
# mylist.append(64) #無異常

#發生異常時,程序是怎樣的?
def test_return():
    print("hello") #這條是會被執行的
    raise Exception("My God, something went wrong") #這裏引起異常後,後面的代碼永遠不會執行,包括return語句
    print("How are you?")
    return "I'm very good"
#test_return()

#經過另一個函數來調用test_return函數,看看效果
def call_test_return():
    print("start call...")
    test_return() #在這裏調用test_return函數
    print("an exception was raised....")
    print("so...")
#call_test_return()
"""
在call_test_return函數中調用test_return函數,在test_return函數中有異常的發生
可是對於call_test_return函數是沒有異常語句的。可爲何連call_test_return函數都中止執行了呢?
緣由是:
    異常拋出會中止在call_test_return函數調用棧內全部代碼的執行
"""

#即然有異常,就要處理它,如何處理?
# try:
#     test_return()
# except: #在這裏捕捉到了異常,所以輸出下面的print語句
#     print("test_return Function An exception occurs") #提示有異常發生
# print("end...")
"""
捕捉了異常,而且在發生異常時應該作什麼,所以,程序沒有被終止掉
對於在test_return函數,在拋出異常的語句以後的代碼是沒有被執行的
一、try語句能夠包含任何可能會發生異常的代碼
二、except語句將捕獲任何類型的異常,而不是捕獲有針對性的異常,它是捕獲全部。
三、那麼如何捕獲指定的異常類型?看下面代碼
"""

#捕捉指定的異常類型
def func_a(number):
    try:
        return 100 / number
    except ZeroDivisionError:
        print("Can not be 0")
# print(func_a(0)) #拋出ZeroDivisionError類型的異常
# print(func_a("abcdef")) #拋出TypeError類型的異常,但目前爲止的代碼,沒有寫捕獲TypeError類型的異常,所以這個異常沒法被捕捉
#也就是說,TypeError異常,不包含在要處理的異常類型中
#那麼如何才能同時捕捉多種類型的異常?改進代碼,以下

def func_b(number):
    try:
        return 100 / number
    except (ZeroDivisionError, TypeError):
        print("Unknown value...")
# print(func_b(0))
# print(func_b("abcdef"))
#很是完美,貌似這兩種異常類型都捕捉到了
#可是,這裏有一個弊端,就是,我想捕獲不一樣類型的異常而且對它們作出不一樣的操做,目前的代碼是沒法實現的,
#那麼,爲了實現這個想法,繼續改進代碼,以下
def func_c(number):
    try:
        return 100 / number
    except ZeroDivisionError:
        print("Unknown value...") #捕獲到ZeroDivisionError異常,就執行此操做
    except TypeError:
        print("Value Type Error...") #捕獲到TypeError異常,就執行這個操做
# func_c(0)
# func_c("abc")
# print(func_c(89))
#所以,很是完美!

#思考一個問題,若是捕獲任何類型的異常再最前面會是什麼狀況?看以下代碼
def func_d(number):
    try:
        return 100 / number
    except Exception: #捕獲任何異常類型
        print("Exception....")
    except ZeroDivisionError:
        print("Unknown value...")
    except TypeError:
        print("Value Type Error...")
# func_d(0)
# func_d("abc")
#效果是,雖然明確知道會發生哪一種類型的異常並有針對性的捕獲,可是捕獲任何類型異常在最前面,致使有針對性的捕獲根本就沒有捕獲
#爲何會這樣?由於ZeroDivisionError,TypeError這些內置的異常類型都是從Exception類繼承而來的,也就是說,已經捕獲了,就不必再去有針對性的捕獲。
#OK,那麼若是將他們的順序反過來(也就是except Exception在最後面),又會是啥狀況?看下面的代碼(下面的代碼去掉了捕獲TypeError類型)
def func_e(number):
    try:
        return 100 / number
    except ZeroDivisionError:
        print("Unknown value...")
    except Exception: #捕獲任何異常類型
        print("all Exception....")
# func_e(0) #這裏引起的是ZeroDivisionError類型的異常
# func_e("abc") #這裏本來是引起TypeError類型的異常,但去掉後所以沒法捕捉,因此由except Exception語句來負責捕獲剩下的全部異常
#經過效果,很是完美,而該在怎樣的應用場景去使用它已經沒必要多說,很顯然知道怎麼去應用它了

"""
有沒有注意到,在上面的例子中,捕獲異常以後所作的操做是打印一句話,
可是實際的操做不僅是打印一句話,也能夠是作別的操做,好比作運算,或者繼續循環,或者斷開鏈接等等操做
有一種狀況是,我不想僅僅只是作操做,我還想知道它所引起的異常的具體信息。那麼如何查看?看下面的代碼
"""
def func_f(number):
    try:
        return 100 / number
    except ZeroDivisionError as err:
        print("[Error]:%s [args]:%s" % (err, err.args))
# func_f(0)
#這裏是經過as關鍵字來捕獲到異常做爲變量來訪問,err.args則是獲取傳給函數的參數
#關鍵字as,在異常中使用,是在python3版本中,而對於python2,則使用的是一個逗號

"""
以前說了,把可能發生異常的代碼丟進try中,那麼若是被丟進try的代碼沒有發生異常呢?
若是沒有異常,不只要執行try中的代碼,而且同時我還須要執行別的操做,
若是有異常的發生,那麼就只捕獲異常,並執行對應的動做,無需執行別的額外操做。
那麼請看下面改進後的代碼
"""
def func_g(number):
    try:
        ret =  100 / number
        print(ret)
    except ZeroDivisionError as err:
        print("[Error]:%s [args]:%s" % (err, err.args))
    else:
        print("calculation done...")
# func_g(5) #傳入5到函數中進行計算,沒有異常,沒有異常而且也要執行else後面的語句,所以達到了目的
# func_g(0) #傳入0,則引起異常,那麼僅僅只是執行了except中的捕獲操做,else後面的語句沒有被執行

"""
上面的代碼彷佛很是完美,我又有一個需求,就是語句不管是否發生異常都將執行我指定的操做
改進以下
"""
def func_h(number):
    try:
        ret =  100 / number
        print(ret)
    except ZeroDivisionError as err:
        print("[Error]:%s [args]:%s" % (err, err.args))
    else:
        print("calculation done...")
    finally:
        print("code end...")
# func_h(0) #傳入0,引起異常,而且,也繼續執行了finally後面語句,可是else則沒有執行,很是完美,達到個人目的
# func_h(8) #傳入的是8,沒有異常則無需捕獲,那麼else是在沒有異常的狀況下才執行,那麼他執行了。這很是正確,finally後面的語句也執行了
#經過看到的效果,finally確實是無論有沒有異常的發生,都確實是會執行
相關文章
相關標籤/搜索