Python學習

第九天

今天我們來說下Python中的異常,以及如何去處理異常。我們在程序編碼中難免會碰到異常,今天我們就要來簡要說明什么是異常,如何處理異常。

1、異常的定義

不論是Python語言、Java語言以及其他任何語言,程序在執(zhí)行的過程中難免會產(chǎn)生的錯誤,這些錯誤都可以稱之為異常。比如列表索引越界、打開不存在的文件等。
就如同下面兩行代碼:

print(str1)
# name 'str1' is not defined
open('error.txt','r')
# No such file or directory: 'error.txt'

2、異常處理

程序中出現(xiàn)異常是難免的,發(fā)生異常時我們需要捕獲處理它,否則程序會終止執(zhí)行。
如下代碼:

#控制臺輸入兩個數(shù)字 求商
print('程序開始')
num1 = int(input('請輸入除數(shù)'))
num2 = int(input('請輸入被除數(shù)'))
print(str(num1)+'除以'+str(num2)+'的結(jié)果是',str(num1/num2))
print('程序結(jié)束')

上述這段代碼其實就是存在問題的,比如我在獲得數(shù)字num1的時候輸入的內(nèi)容不可以轉(zhuǎn)換為int(比如你輸入wasd),這個時候就出現(xiàn)異常了。
ValueError: invalid literal for int() with base 10: 'wasd'
其實就是將非數(shù)字字符串轉(zhuǎn)換為整型出現(xiàn)的異常;
如果你在獲得num2的時候,如果輸入了0也會出現(xiàn)異常,
ZeroDivisionError: division by zero
其實就是除以0的原因?qū)е碌摹?br> 并且我們發(fā)現(xiàn)上述兩種異常任何一種異常出現(xiàn),我們的程序就停止了,并且程序沒有往下執(zhí)行,因為我們在控制臺看不到最后一行print的輸出。
這時候就需要我們異常處理了。

2.1、異常類

在Python中,所有異常都是基類Exception的成員,它們都定義在exceptions模塊中。
如果這個異常對象沒有進行處理和捕捉,程序就會用所謂的回溯(traceback,一種錯誤信息)終止執(zhí)行,這些信息包括錯誤的名稱(例如NameError)、原因和錯誤發(fā)生的行號。下面簡單說下我們經(jīng)常遇見的幾個異常:
1、NameError
嘗試訪問一個未聲明的變量,會引發(fā)NameError。

print(str1)
# NameError: name 'str1' is not defined

2、ZeroDivisionError
當除數(shù)為零的時候,會引發(fā)ZeroDivisionError異常。

a = 10/0
print(a)
# ZeroDivisionError: division by zero

**3、SyntaxError **
當解釋器發(fā)現(xiàn)語法錯誤時,會引發(fā)SyntaxError異常。

a = 10
if a == 10
    print('賓果!')
# SyntaxError: invalid syntax

4、IndexError
當使用序列中不存在的索引時,會引發(fā)IndexError異常。

list = [1,2,3,4]
a = list[4]
print(a)
# IndexError: list index out of range

5、KeyError
當使用映射中不存在的鍵時,會引發(fā)KeyError異常。

mydict = {'name':'張三','age':18}
address = mydict['address']
print(address)
# KeyError: 'address'

**6、FileNotFoundError **
試圖打開不存在的文件時,會引發(fā)FileNotFoundError。

file = open('a.txt','r')
# FileNotFoundError: [Errno 2] No such file or directory: 'a.txt'

7、AttributeError
當嘗試訪問未知對象屬性時,會引發(fā)AttributeError異常。

class Settings():
   def _init_(self):
       self.scren_width=1200
       self.screen_height=800
       self.bg_color=(230,230,230)
if __name__ == '__main__':
   a = Settings()
   print(a.scren_width)
# AttributeError: 'Settings' object has no attribute 'scren_width'

2.2、異常處理

在python中,try-except語句定義了監(jiān)控異常的一段代碼,并提供了處理異常的機制。

1、捕獲指定異常

try:
        # 可能會出現(xiàn)異常的語句塊
except <異常種類>:
        # 異常處理代碼
print('程序開始')
try:
    a = 10/0
    print(a)
except ZeroDivisionError as e:
    print('捕獲異常-零不可以是除數(shù)',e)
print('程序繼續(xù)執(zhí)行')
# 程序開始
# 捕獲異常-零不可以是除數(shù) division by zero
# 程序繼續(xù)執(zhí)行

注意,exception后捕獲的異常必須和try代碼塊中出現(xiàn)的異常種類一致,才可以捕獲,否則依然會出現(xiàn)異常,影響其后代碼的執(zhí)行。

print('程序開始')
try:
    a = 10/0
    print(a)
except FileNotFoundError as e:
    print('捕獲異常-文件找不到',e)
print('程序繼續(xù)執(zhí)行')
# ZeroDivisionError: division by zero

2、捕獲多個異常

捕獲多個異常有兩種方式,第一種是一個except同時處理多個異常,不區(qū)分優(yōu)先級。

try:
     # 可能會出現(xiàn)異常的語句塊
except (<異常名1>, <異常名2>, ...): 
      # 異常處理代碼
print('程序開始')
try:
   num1 = int(input('請輸入除數(shù)'))
   num2 = int(input('請輸入被除數(shù)'))
   print(str(num1)+'除以'+str(num2)+'的結(jié)果是',str(num1/num2))
except (ZeroDivisionError,ValueError):
   print('出現(xiàn)異常了')
print('程序繼續(xù)執(zhí)行')

還有第二種方式,是區(qū)分優(yōu)先級的。

try:
        # 可能會出現(xiàn)異常的語句塊
except <異常種類1>:
        # 異常處理代碼1
except <異常種類2>:
        # 異常處理代碼2
except <異常種類3>:
        # 異常處理代碼3
print('程序開始')
try:
   num1 = int(input('請輸入除數(shù)'))
   num2 = int(input('請輸入被除數(shù)'))
   print(str(num1)+'除以'+str(num2)+'的結(jié)果是',str(num1/num2))
except ZeroDivisionError as e1:
   print('出現(xiàn)異常了',e1)
except ValueError as e2:
   print('出現(xiàn)異常了',e2)
print('程序繼續(xù)執(zhí)行')

3、異常中的else

如果try語句沒有捕獲到任何的錯誤信息,就不再執(zhí)行任何except語句,而是會執(zhí)行else語句。

try:
        # 可能會出現(xiàn)異常的語句塊
except <異常種類1>:
        # 異常處理代碼1
except <異常種類2>:
        # 異常處理代碼2
except <異常種類3>:
        # 異常處理代碼3
else:
    # try語句中沒有異常則執(zhí)行此段代碼
import  os
print('程序開始執(zhí)行')
try:
    wfile = open('2.txt','w',encoding='utf-8')
    wfile.write('這是測試文件寫入的內(nèi)容')
except IOError as e:
    print('IO異常',2)
else:
    print('內(nèi)容寫入成功')
    wfile.close()
print('程序繼續(xù)執(zhí)行')
# 程序開始執(zhí)行
# 內(nèi)容寫入成功
# 程序繼續(xù)執(zhí)行

4、捕獲所有的異常

當程序中出現(xiàn)大量異常時,捕獲這些異常是非常麻煩的。這時,我們可以在except子句中不指明異常的類型,這樣,不管發(fā)生何種類型的異常,都會執(zhí)行except里面的處理代碼。

print('程序開始')
try:
   num1 = int(input('請輸入除數(shù)'))
   num2 = int(input('請輸入被除數(shù)'))
   print(str(num1)+'除以'+str(num2)+'的結(jié)果是',str(num1/num2))
except:
   print('出現(xiàn)異常了')
print('程序繼續(xù)執(zhí)行')

5、終止行為(finally)

在程序中,無論是否捕捉到異常,都必須要執(zhí)行某件事情,例如關(guān)閉文件、釋放鎖等,這時可以提供finally語句處理。通常情況下,finally用于釋放資源。

str = 'hello python'
try:
    a = int(str)
except IndexError as e1:
    print('出現(xiàn)異常',e1)
except KeyError as e2:
    print('出現(xiàn)異常',e2)
except ValueError as e3:
    print('出現(xiàn)異常',e3)
else:
    print('try內(nèi)沒有異常')
finally:
    print('無論異常與否,都會執(zhí)行我')

3、raise語句

python是否可以在程序的指定位置手動拋出一個異常?答案是肯定的,python 允許我們在程序中手動設(shè)置異常,使用 raise 語句即可。類似Java中的throw。
語法:raise [exceptionName [(reason)]]
其中,用 [] 括起來的為可選參數(shù),其作用是指定拋出的異常名稱,以及異常信息的相關(guān)描述。如果可選參數(shù)全部省略,則 raise 會把當前錯誤原樣拋出;如果僅省略 (reason),則在拋出異常時,將不附帶任何的異常描述信息。
簡而言之就是使用raise語句能顯示地觸發(fā)異常。
格式如下:
1、raise 異常類名 引發(fā)指定異常類的實例
2、raise 異常類對象 引發(fā)指定異常類的實例
3、raise 重新引發(fā)剛剛發(fā)生的異常

3.1、使用類名引發(fā)異常

print('程序開始執(zhí)行')
try:
    a = input('請輸入一個數(shù)字')
    #判斷用戶輸入的是否為數(shù)字
    if(not a.isdigit()):
        raise ValueError("輸入的必須是數(shù)字") #人為扔出異常
except ValueError as e:
    print("引發(fā)異常:",repr(e))
print('程序繼續(xù)執(zhí)行')
# 程序開始執(zhí)行
# 請輸入一個數(shù)字wasd
# 引發(fā)異常: ValueError('輸入的必須是數(shù)字')
# 程序繼續(xù)執(zhí)行

3.2、使用異常類的實例引發(fā)異常

print('程序開始執(zhí)行')
try:
    a = input('請輸入一個數(shù)字')
    #判斷用戶輸入的是否為數(shù)字
    if(not a.isdigit()):
        err = ValueError()
        raise err
except ValueError as e:
    print("引發(fā)異常:",repr(e))
print('程序繼續(xù)執(zhí)行')

3.3、raise傳遞異常

不帶任何參數(shù)的raise語句,可以再次引發(fā)剛剛發(fā)生過的異常,作用就是向外傳遞異常。

print('程序開始執(zhí)行')
try:
    a = input('請輸入一個數(shù)字')
    #判斷用戶輸入的是否為數(shù)字
    if(not a.isdigit()):
        raise ValueError("輸入的必須是數(shù)字")
except ValueError as e:
    print("引發(fā)異常:",repr(e))
    raise
print('程序繼續(xù)執(zhí)行')
# ValueError: 輸入的必須是數(shù)字

4、assert語句

assert語句又稱作斷言,指的是期望用戶滿足指定的條件。
當用戶定義的約束條件不滿足的時候,它會觸發(fā)AssertionError異常,所以assert語句可以當做條件式的raise語句。
assert語句格式如下:
assert 邏輯表達式,data
相當于:
if not 邏輯表達式:
raise AssertionError(data)
assert后面緊跟一個邏輯表達式,相當于條件。Data通常是一個字符串,當條件為false時作為異常的描述信息。

print('程序開始執(zhí)行')
a = int(input('請輸入除數(shù)'))
assert a != 0,'除數(shù)不可以為0'
# AssertionError: 除數(shù)不可以為0

5、自定義異常

python允許我們自定義異常,只需要兩步:
1、創(chuàng)建一個繼承Exception類的子類,就是自定義異常類。
2、當遇到自己設(shè)定的錯誤時,使用raise語句拋出自定義的異常。

#自定義異常類
class MyErr(Exception):
    def __init__(self,args):
        self.args = args
#觸發(fā)自定義異常
if __name__ == '__main__':
    print('程序開始執(zhí)行')
    try:
        raise MyErr('這是我自定義的異常')
    except MyErr as e:
        print('出現(xiàn)的異常為',e.args)

6、總結(jié)

這次主要針對Python的異常進行介紹,包括異常類、拋出和捕捉系統(tǒng)內(nèi)置的異常、拋出和捕捉自定義異常,大家應(yīng)該深入了解了異常產(chǎn)生的原理,并知道如何在程序中運行它們。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容