在python中,try/except語句也主要是用於處理程序正常執行過程中出現的一些異常情況,常見的異常如下:
python程序在發現了except之后的某個錯誤時,往往會中斷不再向下執行
try/except格式:
try:
normal excute block
except A:
Except A handle
except B:
Except B handle
.........
except:
other exception handle
else:
if no exception,get here
finally:
print(hello world)
當try代碼塊執行出現異常,在except中匹配到了A的異常,則執行了對應A handle的語句;在except中匹配到了B的異常,則執行了對應B handle的語句;沒有在列出的異常中則執行except語句,並相應的執行other handle。
注意⚠️:區別except A語句和單獨的except 語句,如果沒有最后的except:語句,當出現的錯誤是代碼中所有except XX語句都不曾列出的異常,則代碼依舊會出現報錯,而非給出handle結果。
通過下面的例子來更好的進行理解:
def divide(x, y): try: result = x / y except ZeroDivisionError, e: print "division by zero! " + str(e) else: print "result is", result finally: print "executing finally clause"
>>> divide(3,4)
result is 0
executing finally clause
可以發現代碼未有報錯,執行到了else語句,且finally語句執行
>>>divide(3,0)
division by zero! integer division or modulo by zero
executing finally clause
可以發現分母為0,執行到了except中的異常語句,且finally語句也執行
>>> divide(3,’0‘)
File "<stdin>", line 1
divide(3,’0‘)
^
SyntaxError: invalid syntax
此時代碼中有string,而函數中必須是要求數字才能執行,但該函數中except語句只定義了一種ZeroDivisionError的異常,所以最后運行報了SyntaxError
對代碼進行優化,如下:
def divideNew(x, y): try: result = x / y except ZeroDivisionError, e: print "division by zero! " + str(e) except TypeError: divideNew(int(x), int(y)) else: print "result is", result finally: print "executing finally clause"
>>> divideNew('4','3')
result is 1
executing finally clause
executing finally clause
可以看到,雖然數字依舊是以string的格式輸入,但執行了except TypeError語句,給出了該異常的handle語句,即int(x),int(y)改變了變量類型;
並且可以看到執行了else語句;
出現了兩次finally語句是因為執行了一次divideNew('4','3'),又執行了一次divideNew(int('4'),int('3')),再次說明finally 是每次都會執行的語句
對於else語句,當出現異常時,else block不執行;而當程序無異常時,才會執行else語句。
對於finally語句,無論try語句是否出現異常,最后都要執行抓斷finally的代碼。
根據上面指出的的標准格式,except x必須在exept語句之前,except必須在else和finally之前,finally必須在else之后(最后)。否則會報語法錯誤。
In Python, can just raise an exception when unable to produce a result consistent with function’s specification
–raise exceptionName(arguments)
Python中,當不能定義某個錯誤時,可以僅僅raise exceptionName(arguments) :
def getRatios(v1, v2): ratios = [] for index in range(len(v1)): try: ratios.append(v1[index]/float(v2[index])) except ZeroDivisionError: ratios.append(float('NaN')) #NaN = Not a Number except: raise ValueError('getRatios called with bad arg') return ratios
可以看到代碼中除去ZeroDivisionError明確指出了錯誤類型和處理方式,其余的異均返回'getRatios called with bad arg'
下面可以進行相應的測試
try: print getRatios([1.0,2.0,7.0,6.0], [1.0,2.0,0.0,3.0]) print getRatios([],[]) print getRatios([1.0,2.0], [3.0]) except ValueError, msg: print msg 結果如下: [1.0, 1.0, nan, 2.0] [] getRatios called with bad argument
這樣分開兩部分編輯的code將便於檢查異常和整理邏輯,也避免了寫在一段函數中的需要考慮的多種情形。
斷言 Assertions
斷言分兩種:pre-Assertions(控制和監督輸入)和post Assertions(監督和控制輸出)
def avg(grades, weights): assert not len(grades) == 0, ‘no grades data’ assert len(grades) == len(weights), ‘wrong number grades’
newgr = [convertLetterGrade(elt) for elt in grades]
result = dotProduct(newgr, weights)/len(newgr) assert 0.0 <= result <= 100.0 return result
第一個pre-Assertions控制了grades變量的輸入值必須是長度非零的變量,否則將要raise an AssertionError:輸出‘no grades data’
第二個pre-Assertions控制了grades變量和weights變量的長度必須一致,否則將要raise an AssertionError:輸出‘wrong number grades
post Assertions則控制了result必須是介於0-100的值才執行return result。
斷言Assertions作為一種防御性編程(defensive programming ),可以對輸入和變量進行限定,以控制其運行進度。