還在Bug不斷?不妨試試這2個(gè)裝__技巧
導(dǎo)讀
程序員每天遇到bug就像喝水吃飯一樣稀松平常,關(guān)鍵在于怎么高效而不失優(yōu)雅的面對(duì)這些bug!所以,你還在固執(zhí)的使用try……except嗎?

為了提高程序運(yùn)行的穩(wěn)健性,幾乎所有語(yǔ)言都提供了try……except……用法,Python也不例外。雖然try……except……語(yǔ)法能夠確保程序能夠跳過(guò)異常代碼片段,無(wú)論如何都繼續(xù)執(zhí)行下去,但有時(shí)主動(dòng)的觸發(fā)報(bào)錯(cuò)和異常也是一種行之有效的程序員裝X護(hù)體方法。
本文主要介紹Python中的兩個(gè)異常相關(guān)的關(guān)鍵字:assert和raise,前者用于斷言發(fā)現(xiàn)潛在異常,后者用于觸發(fā)報(bào)錯(cuò),實(shí)際上二者功能有很大相近之處。
Python內(nèi)置了數(shù)十種Exception/Error類型,例如常見(jiàn)的如下幾種:
IndexError,索引錯(cuò)誤,例如引用了超出列表長(zhǎng)度的索引
KeyError,鍵值錯(cuò)誤,例如引用了字典中不存在的鍵值
NameError,未聲明錯(cuò)誤,例如引用了未賦值的對(duì)象或變量
SyntaxError,語(yǔ)法錯(cuò)誤,廣泛存在
IndentationError,縮進(jìn)錯(cuò)誤,這是Python摒棄花括號(hào)而用縮進(jìn)區(qū)分代碼段的特色產(chǎn)物
TypeError,類型錯(cuò)誤,例如執(zhí)行數(shù)字和字符串相加會(huì)引發(fā)此類錯(cuò)誤
這些錯(cuò)誤很常見(jiàn),也比較直觀易懂。但有沒(méi)有考慮過(guò)主動(dòng)觸發(fā)這些錯(cuò)誤呢?
assert一般用于函數(shù)和類的內(nèi)部,在執(zhí)行具體邏輯前首先對(duì)輸入?yún)?shù)和程序執(zhí)行狀態(tài)進(jìn)行一定的檢查和預(yù)判,僅當(dāng)執(zhí)行狀態(tài)滿足時(shí)才繼續(xù)執(zhí)行后續(xù)的邏輯,否則斷言條件不滿足,引發(fā)后續(xù)的提示。
1assert?"條件判斷",?"條件不滿足時(shí)輸出的提示信息"
例如,設(shè)計(jì)一個(gè)兩數(shù)相除的函數(shù),那么應(yīng)當(dāng)在執(zhí)行相除前檢查:
?兩個(gè)輸入?yún)?shù)是否為數(shù)值型
除數(shù)是否不為0
這一條件判斷可用assert完成,并在條件不滿足時(shí)優(yōu)雅的提示報(bào)錯(cuò):
1def?div(x,?y):
2????assert?isinstance(x,?(float,?int))?and?isinstance(y,?(float,?int)),?\
3????????????????"param?`x`?and?`y`?expected?to?be?'int'?or?'float'?type"
4????assert?y?!=?0,?"param?`y`?should?not?to?be?exactly?`0`"
5????return?x/y
6
7div(1,?"2")
8---------------------------------------------------------------------------
9AssertionError????????????????????????????Traceback?(most?recent?call?last)
10-206-579e0bede4d8>?in?
11---->?1?div(1,?"2")
12
13-205-258ec937e818>?in?div(x,?y)
14??????1?def?div(x,?y):
15??????2?????assert?isinstance(x,?(float,?int))?and?isinstance(y,?(float,?int)),?\
16---->?3?????????????????"param?`x`?and?`y`?expected?to?be?'int'?or?'float'?type"
17??????4?????assert?y?!=?0,?"param?`y`?should?not?to?be?exactly?`0`"
18??????5?????return?x/y
19
20AssertionError:?param?`x`?and?`y`?expected?to?be?'int'?or?'float'?type
由于輸入?yún)?shù)y是字符串類型,斷言失敗,引發(fā)斷言錯(cuò)誤
相較于try……except……用法,assert的最大意義在于能夠及時(shí)發(fā)現(xiàn)程序中未按預(yù)期狀態(tài)執(zhí)行的錯(cuò)誤,這在多人協(xié)作coding過(guò)程中,比except更能提供豐富的報(bào)錯(cuò)信息。
實(shí)際上,raise關(guān)鍵字的哲學(xué)與assert是有相通之處的,只不過(guò)assert包含邏輯判斷和觸發(fā)提示信息兩部分內(nèi)容,而raise則只用于手動(dòng)觸發(fā)異常,且一般觸發(fā)的是Python內(nèi)置異常類型。某種程度上,raise的靈活性要比assert低,在個(gè)人實(shí)際使用過(guò)程中也幾乎很少用到。
1raise?異常類名稱(描述信息)
1def?div(x,?y):
2????if?not?isinstance(x,?(float,?int))?or?not?isinstance(y,?(float,?int)):
3????????raise?TypeError("param?`x`?and?`y`?expected?to?be?'int'?or?'float'?type")
4????if?y?==?0:
5????????raise?ZeroDivisionError("param?`y`?should?not?to?be?exactly?`0`")
6????return?x/y
7
8div(1,?0)
9---------------------------------------------------------------------------
10ZeroDivisionError?????????????????????????Traceback?(most?recent?call?last)
11-213-4267cdef819f>?in?
12---->?1?div(1,?0)
13
14-212-dce337c4d91a>?in?div(x,?y)
15??????3?????????raise?TypeError("param?`x`?and?`y`?expected?to?be?'int'?or?'float'?type")
16??????4?????if?y?==?0:
17---->?5?????????raise?ZeroDivisionError("param?`y`?should?not?to?be?exactly?`0`")
18??????6?????return?x/y
19
20ZeroDivisionError:?param?`y`?should?not?to?be?exactly?`0`
由于除數(shù)為0,raise關(guān)鍵字觸發(fā)異常
以上就是Python中這兩個(gè)關(guān)鍵字的簡(jiǎn)單用法,單論其實(shí)質(zhì)功能而言都稱不上是不可或缺,甚至可能會(huì)覺(jué)得有些雞肋,但不得不說(shuō)在某些場(chǎng)景下二者其實(shí)都還是有用武之地,或許屆時(shí)你的代碼也可以如大佬一般:優(yōu)雅高效,同時(shí)略顯裝__!

相關(guān)閱讀:

