Python例外處理機制到底有什麼用?

2020-07-16 10:05:20
例外處理是現代程式語言不可或缺的能力,它已經成為衡量一門程式語言是否成熟和健壯的標準之一,C++、Java、C#、Python 等高階語言都提供了例外處理機制。

無論你是多麼優秀的程式設計師,你都不能保證自己的程式永遠不會出錯。就算你的程式沒有錯,使用者也不一定按照你設定的規則來使用你的程式,總有一些小白或者極客會“玩弄”你的程式。

除此以外,你也不能保證程式的執行環境永遠穩定,比如作業系統可能崩潰,網路可能無法連線,記憶體可能突然壞掉……

總之,你基本什麼都保證不了。但是,作為一個負責任的程式設計師,我們要讓自己的程式盡可能的健壯,盡可能保證在惡劣環境下還能正常執行,或者給使用者提示錯誤,讓使用者決定是否退出。

例如有一個五子棋程式,當使用者輸入落子的坐標時,程式既要判斷輸入格式是否正確(橫坐標和縱坐標之間由逗號分隔),還要判斷坐標是否在合法的範圍內。一般我們都會這樣來處理:

if 坐標包含了除逗號之外的其它非數位字元:
    alert 坐標只能是數值
    goto retry
elif 坐標不包含逗號:
    alert 必須使用逗號分隔橫坐標和縱坐標
    goto retry
elif 坐標落在了棋盤外:
    alert 坐標必須位於棋盤之內
    goto retry
elif 作為位置已有其它棋子:
    alert 只能在沒有棋子的位置落子
    goto retry
else:
    #正常的業務程式碼
    ......

上面的程式碼並沒有涉及所有出錯情形,只是考慮了四種可能出錯的情形,程式碼量就已經急劇增加了。

在實際開發中,不可預料的情況呈數量級增長,甚至不能窮舉,按照上面的邏輯來處理各種錯誤簡直讓人抓狂。

如果每次在實現真正的業務邏輯之前,都需要不厭其煩地考慮各種可能出錯的情況,針對各種錯誤情況給出補救措施,這是多麼乏味的事情啊。程式設計師喜歡解決問題,喜歡開發帶來的“創造”快感,但不喜歡像一個“堵漏”工人,去堵那些由外在條件造成的“漏洞”。

對於構造大型、健壯、可維護的應用而言,錯誤處理是整個應用需要考慮的重要方面,程式設計師不能僅僅只做“對”的事情,程式設計師開發程式的過程,是一個創造的過程,這個過程需要有全面的考慮,僅做“對”的事情是遠遠不夠的。

對於上面的錯誤處理機制,主要有如下兩個缺點:
  • 無法窮舉所有的異常情況。因為人類知識的限制,異常情況總比可以考慮到的情況多,總有“漏網之魚”的異常情況,所以程式總是不夠健壯。
  • 錯誤處理程式碼和業務實現程式碼混雜。這種錯誤處理和業務實現混雜的程式碼嚴重影響程式的可讀性,會增加程式維護的難度。

程式設計師希望有一種強大的機制來解決上面的問題,能夠將上面程式改成如下的形式:

if 使用者輸入不合法:
    alert 輸入不合法
    goto retry
else :
    #正常的業務程式碼
    ......

上面偽碼提供了一個非常強大的“if 塊”,即程式不管輸入錯誤的原因是什麼,只要使用者輸入不滿足要求,程式就一次處理所有的錯誤。這種處理方法的好處是,使得錯誤處理程式碼變得更有條理,只需在一個地方處理錯誤。

現在的問題是,“使用者輸入不合法”這個條件怎麼定義?當然,對於這個簡單的要求,可以使用正規表示式對使用者輸入進行匹配,當使用者輸入與正規表示式不匹配時即可判斷“使用者輸入不合法”。但對於更複雜的情形,就沒有這麼簡單了。使用 Python 的例外處理機制就可以解決這個問題,例如:

try:
    if(使用者輸入不合理):
        raise 異常
except Exception:
    alert 輸入不合法
    goto retry
#正常的業務程式碼

此程式中,通過在 try 塊中判斷使用者的輸入資料是否合理,如果不合理,程式受 raise 的影響會進行到 except 程式碼塊,對使用者的錯誤輸出進行處理,然後會繼續執行正常的業務程式碼;反之,如果使用者輸入合理,那麼程式將直接執行正常的業務程式碼。

try except 是 Python 實現例外處理機制的核心結構,其具體用法會在後續章節做詳細介紹。

顯然,使用 Python 例外處理機制,可以讓程式中的例外處理程式碼和正常業務程式碼分離,使得程式程式碼更加優雅,並可以提高程式的健壯性。