本節書摘來自華章社群《編寫高品質python代碼的59個有效方法》一書中的第13條:合理利用try/except/else/f?inally結構中的每個代碼塊,作者[美]布雷特·斯拉特金(brett slatkin),更多章節内容可以通路雲栖社群“華章社群”公衆号檢視
第13條:合理利用try/except/else/f?inally結構中的每個代碼塊
python程式的異常處理可能要考慮四種不同的時機。這些時機可以用try、except、else和f?inally塊來表述。複合語句中的每個塊都有特定的用途,它們可以構成很多種有用的組合方式(參見本書第51條)。
1.?f?inally塊
如果既要将異常向上傳播,又要在異常發生時執行清理工作,那就可以使用try/f?inally結構。這種結構有一項常見的用途,就是確定程式能夠可靠地關閉檔案句柄(還有另外一種寫法,參見本書第43條)。
在上面這段代碼中,read方法所抛出的異常會向上傳播給調用方,而f?inally塊中的handle.close方法則一定能夠執行。open方法必須放在try塊外面,因為如果打開檔案時發生異常(例如,由于找不到該檔案而抛出ioerror),那麼程式應該跳過f?inally塊。
2.else塊
try/except/else結構可以清晰地描述出哪些異常會由自己的代碼來處理、哪些異常會傳播到上一級。如果try塊沒有發生異常,那麼就執行else塊。有了這種else塊,我們可以盡量縮減try塊内的代碼量,使其更加易讀。例如,要從字元串中加載json字典資料,然後傳回字典裡某個鍵所對應的值。
如果資料不是有效的json格式,那麼用json.loads解碼時,會産生valueerror。這個異常會由except塊來捕獲并處理。如果能夠解碼,那麼else塊裡的查找語句就會執行,它會根據鍵來查出相關的值。查詢時若有異常,則該異常會向上傳播,因為查詢語句并不在剛才那個try塊的範圍内。這種else子句,會把try/except後面的内容和except塊本身區分開,使異常的傳播行為變得更加清晰。
3.混合使用
如果要在複合語句中把上面幾種機制都用到,那就編寫完整的try/except/else/f?inally結構。例如,要從檔案中讀取某項事務的描述資訊,處理該事務,然後就地更新該檔案。為了實作此功能,我們可以用try塊來讀取檔案并處理其内容,用except塊來應對try塊中可能發生的相關異常,用else塊實時地更新檔案并把更新中可能出現的異常回報給上級代碼,然後用f?inally塊來清理檔案句柄。
這種寫法很有用,因為這四塊代碼互相配合得非常到位。例如,即使else塊在寫入result資料時發生異常,f?inally塊中關閉檔案句柄的那行代碼,也依然能執行。
要點
無論try塊是否發生異常,都可利用try/f?inally複合語句中的f?inally塊來執行清理工作。
else塊可以用來縮減try塊中的代碼量,并把沒有發生異常時所要執行的語句與try/except代碼塊隔開。
順利運作try塊後,若想使某些操作能在f?inally塊的清理代碼之前執行,則可将這些操作寫到else塊中。