零基礎學Python--------第9章 異常處理及程序調試

第9章 異常處理及程序調試

9.1 異常概述

在程序運行過程當中,常常會遇到各類各樣的錯誤,這些錯誤統稱爲「異常」。這些異常有的是因爲開發者將關鍵字敲錯致使的,這類錯誤多數產生的是SyntaxError:invalid syntax(無效的語法),這將直接致使程序不能運行。這類異常是顯式的,在開發階段很容易被發現。還有一類是隱式的,一般和使用者的操做有關。app

實例01:模擬幼兒園分蘋果函數

def division():
    '''功能:分蘋果'''
    print("\n=====================分蘋果======================\n")
    apple = int(input("請輸入蘋果的個數:"))                         # 輸入蘋果的數量
    children = int(input("請輸入來了幾個小朋友:"))
    result = apple//children                                         # 計算每人分幾個蘋果
    remain = apple-result*children                                   # 計算餘下幾個蘋果
    if remain>0:
        print(apple,"個蘋果,平均分給",children,"個小朋友,每人分",result,"個,剩下",remain,"個。")
    else:
        print(apple,"個蘋果,平均分給",children,"個小朋友,每人分",result,"個。")
if __name__ == '__main__':
    division()                                                       # 調用分蘋果的函數

 

運行程序,當輸入蘋果和小朋友的數量都是10時:spa

請輸入蘋果的個數:10
請輸入來了幾個小朋友:10
10 個蘋果,平均分給 10 個小朋友,每人分 1 個。

 

若是在輸入數量時,不當心把小朋友的人數輸成了0:3d

產生了ZeroDivisionError(除數爲0錯誤)的根源在於算術表達式「10/0」中,0做爲除數出現,因此正在執行的程序中被中斷(第6行之後,包括第6行的代碼都不會被執行)。調試

Python中還有不少異常。code

Python中常見的異常
異常 描述
NameError 嘗試訪問一個沒有聲明的變量引起的錯誤
IndexError 索引超出序列範圍引起的錯誤
IndentationError 縮進錯誤
ValueError 傳入錯誤
KeyError 請求一個不存在的字典關鍵字引起的錯誤
IOError 輸入輸出錯誤(如要讀取的文件不存在)
ImportError 當import語句沒法找到模塊或from 沒法在模塊中找到相應的名稱時引起的錯誤
AttributeError 嘗試訪問未知的對象屬性引起的錯誤
TypeError 類型不合適引起的錯誤
MemoryError 內存不足
ZeroDivisionError 除數爲0 引起的錯誤

9.2 異常處理語句

在程序開發時,有些錯誤並非每次運行都會出現。對象

下面將詳細介紹Python中提供的異常處理語句。blog

9.2.1 try...eccept

在Python中,提供了try...except語句捕獲並處理異常。在使用時,把可能產生異常的代碼放在try 語句塊中,把處理結果放在except 語句塊中,這樣,當try 語句塊中的代碼出現錯誤時,就會執行except語句塊中的代碼,若是try 語句塊中的代碼沒有錯誤,那麼except 語句塊將不會執行。具體的語法格式以下:索引

try:
    block1    
except [ExceptionName [as alias]]:
    block2

 

參數說明:內存

  • block1:表示可能出現錯誤的代碼塊。
  • ExceptionName [as alias]:可選參數,用於指定要捕獲的異常。其中,ExceptionName表示要捕獲的異常名稱,若是在其右側加上as alias,則表示爲當前的異常指定一個別名,經過該別名,能夠記錄異常的具體內容。

說明:在使用try...except語句捕獲異常時,若是在except後面不指定異常名稱,則表示捕獲所有異常。

  • block2:表示進行異常處理的代碼塊。在這裏能夠輸出固定的提示信息,也能夠經過別名輸出異常的具體內容。

說明:使用try...except語句捕獲異常後,當程序出錯時,輸出錯誤信息後,程序會繼續執行。

 實例02:模擬幼兒園分蘋果(除數不能爲0)

對「if __name__ =='__main__':」語句下面的代碼進行修改,應用try...except語句捕獲執行division()函數可能拋出的ZeroDivisionError(除數爲零)異常,修改後的代碼以下:

def division():
    '''功能:分蘋果'''
    print("\n=====================分蘋果======================\n")
    apple = int(input("請輸入蘋果的個數:"))                         # 輸入蘋果的數量
    children = int(input("請輸入來了幾個小朋友:"))
    result = apple//children                                         # 計算每人分幾個蘋果
    remain = apple-result*children                                   # 計算餘下幾個蘋果
    if remain>0:
        print(apple,"個蘋果,平均分給",children,"個小朋友,每人分",result,"個,剩下",remain,"個。")
    else:
        print(apple,"個蘋果,平均分給",children,"個小朋友,每人分",result,"個。")
if __name__ == '__main__':
    try:                                                                 # 捕獲異常
        division()                                                       # 調用分蘋果的函數
    except ZeroDivisionError:                                            # 處理異常
        print("\n出錯了 ~_~ ——蘋果不能被0個小朋友分!")

 

執行以上的代碼,輸入蘋果的數量爲10,小朋友的人數爲0時,將再也不拋出異常:

目前,咱們只處理了除數爲0的狀況,若是將蘋果和小朋友的數量輸入成小數或者不是數字會是什麼結果呢?

能夠看出,程序中要求輸入整數,而實際輸入的是小數,則拋出ValueError(傳入的值錯誤)異常。要解決該問題,能夠在實例02的代碼中,爲try...except語句再添加一個except語句,用於處理拋出ValueError異常的狀況。修改後的代碼以下:

def division():
    '''功能:分蘋果'''
    print("\n=====================分蘋果======================\n")
    apple = int(input("請輸入蘋果的個數:"))                         # 輸入蘋果的數量
    children = int(input("請輸入來了幾個小朋友:"))
    result = apple//children                                         # 計算每人分幾個蘋果
    remain = apple-result*children                                   # 計算餘下幾個蘋果
    if remain>0:
        print(apple,"個蘋果,平均分給",children,"個小朋友,每人分",result,"個,剩下",remain,"個。")
    else:
        print(apple,"個蘋果,平均分給",children,"個小朋友,每人分",result,"個。")
if __name__ == '__main__':
    try:                                                                 # 捕獲異常
        division()                                                       # 調用分蘋果的函數
    except ZeroDivisionError:                                            # 處理異常
        print("\n出錯了 ~_~ ——蘋果不能被0個小朋友分!")
    except ValueError as e:                                              # 處理ValueError異常
        print("輸入錯誤:",e)                                             # 輸出錯誤緣由

 

再次運行程序:

多學兩招:

在捕獲異常時,若是須要同時處理多個異常也能夠採用下面的代碼實現:

try:                                                                 # 捕獲異常
        division()                                                       # 調用分蘋果的函數
    except (ZeroDivisionError,ValueError) as e:                          # 處理異常
        print("輸入錯誤:",e)                                            # 輸出錯誤緣由

 

即在except語句後面使用一對小括號將可能出現的異常名稱括起來,多個異常名稱之間使用逗號分隔。若是想要顯示具體的出錯緣由,那麼再加上as指定一個別名。

9.2.2 try...except...else 語句

在Python中國,還有另外一種異常處理結構,它是try...except...else語句,也就是在原來try...except語句的基礎上再添加一個else子句,用於指定當try語句塊中沒有發現異常時要執行的語句塊。該語句塊中的內容當try語句中發現異常,將不被執行。例如,實例02進行修改,實現當division()函數被執行後沒有拋出異常時,輸出文字「分蘋果順利完成...」。修改後的代碼以下:

def division():
    '''功能:分蘋果'''
    print("\n=====================分蘋果======================\n")
    apple = int(input("請輸入蘋果的個數:"))                         # 輸入蘋果的數量
    children = int(input("請輸入來了幾個小朋友:"))
    result = apple//children                                         # 計算每人分幾個蘋果
    remain = apple-result*children                                   # 計算餘下幾個蘋果
    if remain>0:
        print(apple,"個蘋果,平均分給",children,"個小朋友,每人分",result,"個,剩下",remain,"個。")
    else:
        print(apple,"個蘋果,平均分給",children,"個小朋友,每人分",result,"個。")
if __name__ == '__main__':
    try:                                                                 # 捕獲異常
        division()                                                       # 調用分蘋果的函數
    except ZeroDivisionError                  :                          # 處理異常
        print("\n出錯了 ~_~ ——蘋果不能被0個小朋友分!")
    except ValueError as e:                                              # 處理ValueError異常
        print("輸入錯誤:",e)                                            # 輸出錯誤緣由
    else:                                                                # 沒有拋出異常時執行
        print("分蘋果順利完成...")

 

執行以上代碼:

9.2.3 try...except...finally 語句

完整的異常處理語句應該包含finally 代碼塊,一般狀況下,不管程序中有無異常產生,finally 代碼塊中的代碼都會被執行,其語法格式以下:

try:
    block1
except [ExceptionName [as alias]]:
    block2
fianlly:
    block3

 

對於try...except...finally 語句的理解並不複雜,它只是比try...except 語句多了一個finally 語句,若是程序中有一些在任何情形中都必須執行的代碼,那麼就能夠將它們放在finally 代碼塊中。

說明:使用except 子句是爲了容許處理異常。不管是否引發了異常,使用finally 子句都是能夠執行清理代碼。若是分配了有限的資源(如打開文件),則應將釋放這些資源的代碼放置在finally 代碼塊中。

例如,在對實例02進行修改,實現當division() 函數在執行時不管是否拋出異常,都輸出文字「進行了一次分蘋果操做」。修改後的代碼以下:

def division():
    '''功能:分蘋果'''
    print("\n=====================分蘋果======================\n")
    apple = int(input("請輸入蘋果的個數:"))                         # 輸入蘋果的數量
    children = int(input("請輸入來了幾個小朋友:"))
    result = apple//children                                         # 計算每人分幾個蘋果
    remain = apple-result*children                                   # 計算餘下幾個蘋果
    if remain>0:
        print(apple,"個蘋果,平均分給",children,"個小朋友,每人分",result,"個,剩下",remain,"個。")
    else:
        print(apple,"個蘋果,平均分給",children,"個小朋友,每人分",result,"個。")
if __name__ == '__main__':
    try:                                                                 # 捕獲異常
        division()                                                       # 調用分蘋果的函數
    except ZeroDivisionError                  :                          # 處理異常
        print("\n出錯了 ~_~ ——蘋果不能被0個小朋友分!")
    except ValueError as e:                                              # 處理ValueError異常
        print("輸入錯誤:",e)                                            # 輸出錯誤緣由
    else:                                                                # 沒有拋出異常時執行
        print("分蘋果順利完成...")
    finally:                                                             # 不管是否拋出異常都執行
        print("進行了一次分蘋果操做。")

 

執行程序:

至此,已經介紹了異常處理語句的try....except、try...except...else 和 try...except...finally 等形式。

異常處理語句的不一樣子句的執行關係

9.2.4 使用raise 語句拋出異常

若是某個函數或方法可能會產生異常,但不想在當前函數或方法中處理這個異常,則可使用raise 語句在函數或方法中拋出異常。raise 語句的語法格式以下:

raise [ExceptionName[(reason)]]

 

其中,ExceptionName[(reason)]爲可選參數,用於指定拋出的異常名稱以及異常信息的相關描述。若是省略,就會把當前的錯誤原樣拋出。

說明:ExceptionName[(reason)]參數中的「(reason)」也能夠省略,若是省略,則在拋出異常時,不附帶任何描述信息。

例如,修改實例02,加入限制蘋果數量必須大於或等於小朋友的數量,從而保證每一個小朋友都能至少分到一個蘋果。

實例03:模擬幼兒園分蘋果(每一個人至少分到一個蘋果)

在第5行代碼「children = int(input("請輸入來了幾個小朋友:"))」的下方添加一個if 語句,實現當蘋果的數量小於小朋友的數量時,應用raise 語句拋出一個ValueError 異常,接下來再在最後一行語句的下方添加except 語句處理ValueError 異常。

def division():
    '''功能:分蘋果'''
    print("\n=====================分蘋果======================\n")
    apple = int(input("請輸入蘋果的個數:"))                         # 輸入蘋果的數量
    children = int(input("請輸入來了幾個小朋友:"))
    if apple < children:
        raise ValueError("蘋果太少了,不夠分...")
    result = apple//children                                         # 計算每人分幾個蘋果
    remain = apple - result*children                                   # 計算餘下幾個蘋果
    if remain>0:
        print(apple,"個蘋果,平均分給",children,"個小朋友,每人分",result,"個,剩下",remain,"個。")
    else:
        print(apple,"個蘋果,平均分給",children,"個小朋友,每人分",result,"個。")
if __name__ == '__main__':
    try:                                                                 # 捕獲異常
        division()                                                       # 調用分蘋果的函數
    except ZeroDivisionError                  :                          # 處理ZeroDivisionError異常
        print("\n出錯了 ~_~ ——蘋果不能被0個小朋友分!")
    except ValueError as e:                                              # ValueError
        print("\n出錯了~_~ ——",e)

 

執行程序:

說明:在應用raise 拋出異常時,要儘可能選擇合理的異常對象,而不該該拋出一個與實際內容不相關的異常。流入,在實例03中,想要處理的是一個和值有關的異常,這時就不該該拋出一個IndentationError異常。

9.3 程序調試

相關文章
相關標籤/搜索