核心知識點:
(1)無論try塊是否發生異常,都可以使用try/finally復合語句中地finally塊來執行清理工作。
(2)順利運行try塊后,若想使某些操作能在finally塊地清理代碼之前執行,則可將這些操作寫入到else塊中
Python程序的異常處理可能要考慮四種不同的時機。這些時機可以用try、expect、else和finally塊來表述。
復合語句中的每個塊都有特定的用途,它們可以構成很多種有用的組合方式。
1.finally塊
如果既要將異常向上傳播,又要在異常發生時執行清理工作,那就可以使用try/finally結構。
這種結構有一項常見的用途,就是確保程序能夠可靠地關閉文件句柄。
>>> handle = open('/tmp/my_file.txt') >>> try: ... data = handle.read() ... finally: ... handle.close()
上面這段代碼中,read方法所拋出的異常會向上傳播給調用方,而finally塊中的handle.close()方法則一定能夠執行。
open方法必須放在try塊外面,應為如果打開文件時發生異常,那么程序應該跳過finally塊。
2.else塊
try/expect/else結構可以清晰地描述出那些異常會由自己的代碼來處理,那些異常會傳播到上一級。
如果try'塊沒有發生異常,那么就執行else塊。有了這種else塊,我們可以盡量縮減try塊內的代碼量,使其更加易懂。
例如,要從字符串中加載JSON字典數據,然后返回字典里某個鍵所對應地值。
>>> def load_json_key(data,key): ... try: ... result_dict = json.loads(data) ... except ValueError as e: ... raise KeyError from e ... else: return result_dict[key]
如果數據不是有效地JSON格式,那么用json.loads解碼時,會產生ValueError。這個異常會由except塊來捕獲並處理。
如果能夠解碼,那么else塊里地查找語句就會執行,它會根據鍵來查出相關地值。查詢時若有異常,則該異常會向上傳播,因為查詢語句並不在剛才那個try塊地范圍內。
這種else子句,會把try/except后面地內容和except塊本身區分開來,使異常地傳播行為變得更加清晰。
3.混合使用
如果要在復合語句中把上面幾種機制都用到,那就編寫完整地try/except/else/fianally結構。
例如,要從文件中讀取某項事務地描述信息,處理該事務,然后就地更新該文件。
為了實現本功能,我們可以用try塊來讀取文件並處理其內容,用except塊來應對try中可能發生地相關問題,
用else塊實時地更新文件並把更新中可能出現地問題回報給上級代碼,然后用finally塊來清理文件句柄。
UNDEFINED = object() def divide_json(path): handle = open(path,'r+') try: data = handle.read() op = json.loada(data) value = ( op['numerator'] / op['denominator']) except ZeroDivisionError as e: return UNDEFINED else: op['result'] = value result = json.dumps(op) handle.seek(0) handle.write(result) return value finally: handle.close()
這種寫法很有用,因為這四塊代碼相互配合非常到位。
文章摘抄於Brett Slatkin的《編寫高質量Python代碼的59個有效方法》,僅作為個人學習使用,如有侵權請告知,將及時刪除,如果覺得有益,請購買原版書籍,知識需要傳遞和支持,謝謝。
