python學(xué)習(xí)筆記-tip45(異常處理機(jī)制--錯(cuò)誤處理)

引言

我們用什么語(yǔ)言寫項(xiàng)目,其實(shí)都會(huì)出錯(cuò),錯(cuò)誤有很多種,有我們寫的代碼本身就有問(wèn)題,這個(gè)時(shí)候?qū)儆诰幾g錯(cuò)誤,有的代碼運(yùn)行的時(shí)候有問(wèn)題,這個(gè)屬于運(yùn)行時(shí)異常,python其實(shí)也有一套自己的異常處理機(jī)制。今天我們來(lái)學(xué)習(xí)一下。

解決錯(cuò)誤中的一種方式:返回錯(cuò)誤碼

返回錯(cuò)誤碼其實(shí)是程序員排除錯(cuò)誤的一種方式,他們往往會(huì)有一個(gè)錯(cuò)誤碼的字典,字典里面記錄了什么數(shù)字對(duì)應(yīng)著什么錯(cuò)誤;然后當(dāng)程序返回什么碼的時(shí)候,去再對(duì)照之前那個(gè)字典,就能夠知道什么錯(cuò)誤了。
但是錯(cuò)誤碼其實(shí)有一個(gè)局限性,就是當(dāng)我們返回的結(jié)果如果和錯(cuò)誤碼混合在一起,那么久不太好區(qū)分了。

為了避免這種問(wèn)題,我們常用try catch finally(java語(yǔ)言中)等方式進(jìn)行運(yùn)行時(shí)異常的捕獲。
當(dāng)然python也有類似的。

try...except...finally

我們先試用一下

    try:
        print('try...')
        r=10/0
        print('result:',r)
    except ZeroDivisionError as e:
        print('except:',e)
    finally:
        print('finally...')
    print('END')

大家應(yīng)該能看懂大概意思,我們來(lái)看下實(shí)際輸出結(jié)果

當(dāng)我們認(rèn)為某些代碼可能會(huì)出錯(cuò)時(shí),就可以用try來(lái)運(yùn)行這段代碼
如果執(zhí)行出錯(cuò),則后續(xù)代碼不會(huì)繼續(xù)執(zhí)行,而是直接跳轉(zhuǎn)至except語(yǔ)句塊
執(zhí)行完except后,如果有finally語(yǔ)句塊,則執(zhí)行finally語(yǔ)句塊
至此,執(zhí)行完畢

ok,當(dāng)然,如果沒(méi)有錯(cuò)誤出現(xiàn),那么也不會(huì)執(zhí)行except代碼塊,如下如


(注意:如果想得到整數(shù),那么用"http://")

從上面的輸出結(jié)果,可以看到,不論異常有沒(méi)有finally一直都會(huì)執(zhí)行,就像java中的一樣

那么,如果發(fā)生了不同種的錯(cuò)誤,是不是可以使用多種except去處理呢?

答案是肯定的!
我們直接來(lái)看示例



這個(gè)例子中,我們用一個(gè) except 來(lái)捕獲 ValueError ,一個(gè) except 來(lái)捕獲 ZeroDivisionError

此外,如果沒(méi)有錯(cuò)誤發(fā)生的話,還可以在 except 后添加一個(gè) else: 去執(zhí)行沒(méi)有該錯(cuò)誤的處理

如下面例子所示


需要注意的是,并不是一個(gè) except 對(duì)應(yīng)一個(gè) else ,而是當(dāng)所有的 except 都沒(méi)處理的話,才會(huì)執(zhí)行唯一的 else ,下面的寫法是錯(cuò)的

錯(cuò)誤寫法

Python的錯(cuò)誤也是類,所以如果想捕獲某一大類的錯(cuò)誤,直接捕獲大類就好了

所有的錯(cuò)誤類,都繼承自 BaseException類

常見(jiàn)的錯(cuò)誤類型和繼承關(guān)系看這里:
https://docs.python.org/3/library/exceptions.html#exception-hierarchy

使用try...except捕獲錯(cuò)誤還有一個(gè)巨大的好處,就是可以跨越多層調(diào)用

請(qǐng)看下方示例:

由此我們發(fā)現(xiàn),有了這個(gè)跨越多層調(diào)用 except ,大大減少了復(fù)雜的 try except finally 代碼的使用

調(diào)用棧

如果出的錯(cuò)沒(méi)有處理,那么最終會(huì)被 python 解釋器捕獲,打印一個(gè)錯(cuò)誤信息,然后程序退出
我們來(lái)演示一下


出錯(cuò)的時(shí)候,一定要分析錯(cuò)誤的調(diào)用棧信息,才能定位錯(cuò)誤的位置

出了錯(cuò)之后要懂得找打錯(cuò)誤的位置,上面的例子錯(cuò)誤的位置就在第三行,10/s的位置,找到錯(cuò)誤的位置,確定錯(cuò)誤的類型,我們就能夠解決了

logging類

我們從上面的例子知道了,即使我們不進(jìn)行異常的捕獲,python編譯器也會(huì)對(duì)異常進(jìn)行處理,我們也能定位到異常的位置,那么還要異常處理干什么?

其實(shí)不然,python處理器雖然會(huì)處理異常,但是在處理的同時(shí),也將程序終止。
其實(shí)我們可以借助logging類去處理,logging類既會(huì)想python處理器一樣將錯(cuò)誤展示出來(lái),也不會(huì)終止程序,如下例所示


拋出錯(cuò)誤

需要明確的是:
錯(cuò)誤是一個(gè) class ,我們捕獲的錯(cuò)誤其實(shí)就是捕獲了該 class 的一個(gè)實(shí)例
所以說(shuō),錯(cuò)誤并不是憑空出現(xiàn)的,而是有意拋出的

python內(nèi)置的函數(shù)會(huì)拋出很多類型的錯(cuò)誤,當(dāng)然我們自己編寫的函數(shù)也可以拋出錯(cuò)誤。
如果要拋出錯(cuò)誤,我們可以根據(jù)需要,可以定義一個(gè)表示錯(cuò)誤的 class ,然后選擇好繼承關(guān)系,
最后用 raise 語(yǔ)句拋出一個(gè)錯(cuò)誤的實(shí)例。

比如,現(xiàn)在定義一個(gè)錯(cuò)誤,讓他繼承ValueError

  class FooError(ValueError):
            pass

然后在適當(dāng)?shù)牡胤綊伋?/p>

  def  foo(s):
         if s==0:
            raise FooError('Foo Error %s' %s)
         return 10/s

這樣,當(dāng)我們調(diào)用foo函數(shù)時(shí),如果我們傳入
0
那么將會(huì)拋出FooError的錯(cuò)誤,并且打印
“Foo Error 0”
否則的話,則會(huì)直接返回 10/s 的返回值
我們來(lái)看一下真實(shí)的案例演示:



但是,我們只有在必要的時(shí)候才會(huì)定義我們自己的錯(cuò)誤類型,在定義錯(cuò)誤類型時(shí),一定要繼承對(duì)父類,否則會(huì)造成麻煩

下面再來(lái)看另外一中處理錯(cuò)誤的方式:重復(fù)拋出錯(cuò)誤

由上圖,我們可以看出,雖然已經(jīng)捕獲了異常:打印出了FooError!
但是又將之前的異常拋出,這是什么操作呢?

這個(gè)操作有的時(shí)候很有必要

有的情況下,由于當(dāng)前函數(shù)不知道怎樣去處理當(dāng)前遇到的錯(cuò)誤,那么最恰當(dāng)?shù)姆绞绞峭蠏仯岉攲诱{(diào)用者去處理。就好比像一個(gè)員工遇到了一個(gè)棘手的問(wèn)題不知道怎么處理,那么他最恰當(dāng)?shù)淖龇ㄊ墙唤o他的上司,如果他的上司也處理不好,那么就會(huì)一直往上拋,直到拋給公司的大老板,讓大老板去處理

注意用法

raise 如果直接寫的話,那么就是把錯(cuò)誤直接原封不動(dòng)的拋給上級(jí)
如果raise 后追加別的錯(cuò)誤類型的話,其實(shí)就完成了把錯(cuò)誤轉(zhuǎn)化成另外一個(gè)類型額操作了,如

    try:
        10/s
    except ZeroDivisionError as e:    
         print('ZeroDivisionError')
         raise ValueError('ValueError')

當(dāng)然了,這種轉(zhuǎn)化只要符合邏輯就可以,但是切忌瞎轉(zhuǎn)化。

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

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

  • python提供了兩個(gè)非常重要的功能來(lái)處理python程序在運(yùn)行中出現(xiàn)的異常和錯(cuò)誤。你可以使用該功能來(lái)調(diào)試pyth...
    _寧采臣閱讀 1,095評(píng)論 0 10
  • 一、簡(jiǎn)介 Python最強(qiáng)大的結(jié)構(gòu)之一就是它的異常處理能力,所有的標(biāo)準(zhǔn)異常都使用類來(lái)實(shí)現(xiàn),都是基類Exceptio...
    隨風(fēng)化作雨閱讀 3,146評(píng)論 0 1
  • 引言 在程序運(yùn)行過(guò)程中(注意是運(yùn)行階段,程序可以通過(guò)編譯),如果JVM檢測(cè)出一個(gè)不可能執(zhí)行的操作,就會(huì)出現(xiàn)運(yùn)行時(shí)錯(cuò)...
    Steven1997閱讀 2,598評(píng)論 1 6
  • 07 【關(guān)于一盟之主的廚藝討論】 吉嬸回家探親,童路出門采貨,甄平黎剛前幾日去了通州分盟。那么大個(gè)江左,上上下下居...
    Serendipityyy閱讀 2,234評(píng)論 0 3
  • 在 iOS 8 及以前,第三方 App 如果想要全局錄屏,只能使用私有 API,詳見(jiàn)非越獄后臺(tái)錄屏。升級(jí)到 iOS...
    Kingsleeeey閱讀 6,443評(píng)論 7 8

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