例外與捕捉

在動態語言中,除了語法上的錯誤造成的 Syntax Error,幾乎所有的錯誤都來自執行期的錯誤,如同前面見過的TypeError 或是 NameError 等都是。

當發生錯誤時,Python會產生 回溯(traceback),這讓我們可以檢視錯誤發生的來源,有的時候一個錯誤是另外一個錯誤所引發的,唯有一層一層的檢視,才能找出錯誤。

不過,在本節中要討論的不是除錯,而是辨識並排除掉一些不是錯誤的錯誤,因為錯誤並不全然都是錯誤,這聽起來有點玄,讓我們舉個讀取檔案的例子,首先我們來看看要讀的檔 test_file:

3 4
1 3

20 19
%%%
88 7
1 2 3
0

來看看我們的程式碼:

with open('test_file') as f:
    for line in f:
        a, b = line.strip().split()
        print(int(a)+int(b))

我們先對第一次出現的方法 split,作解說,split 是字串的方法,他能夠將字串依照指定的分隔符號切割。

舉例來說:

  • 字串 string='hello,world' 可以利用 string.split(',') 來切割成 'hello''world'
  • 字串 string='hello-world' 可以利用 string.split('-') 來切割成 'hello''world'

如果我們不給定參數,則預設會用空白分割,比如說:

  • 字串string='hello world' 可以利用 string.split() 來切割成 'hello''world'

因此這個程式首先打開了我們的檔案 f,接著利用 for 迴圈去取出每一行字串,取出的字串先用 strip 方法作一個清理,接著使用 split 方法利用空白符號作切割,我們切割成兩個字串 ab(a, b = line.strip().split() 這種寫法就是 unpack,我們會將拆解完的結果依序賦值給 a, b),最後將兩個字串轉成整數後相加。

但我們發現執行的時候出現了 ValueError,這很正常,因為檔案中有許多行並不符合兩個整數的格式,有的行是空白行,有的行有三個整數或只有一個整數,還有的行是奇怪的符號。

如果我們要利用 if/else 的手法來排掉這些 "例外" 的狀況,會顯地非常複雜,每一種可能有誤的格式都需要寫一個 ifelif 來避開,我們與其花大量的時間來避開錯誤,不如讓錯誤發生,我們再來處理,讓會中斷程式的錯誤僅僅是允許繼續執行的例外:

with open('test_file') as f:
    for line in f:
        try:
            a, b = line.strip().split()
            print(int(a)+int(b))
        except:
            pass

例外的捕捉,用的語法是 tryexcept,我們先 try 一段程式碼,如果發生了錯誤,我們立刻停止 try,進入 except suite 做例外發生時的處置。

所以當我讀到非兩個整數的行時會導致錯誤發生,但因為我們只是 try,我們當場捕捉到了這個錯誤 (例外),於是我們就不往下執行 print,而是直接跳至 except suite 去執行,但因為這邊是個空運算,所以等於是我們略過了所有不符合規格的行。

這裡我們看到了空運算的用途,Python 不允許任何一個 suite 是空白的,所以當我們什麼都不想處理時,必須補上一個 pass

讀者越熟悉例外,越會覺得他威力無窮,很多很複雜、很瑣碎很難想清楚的狀況,與其利用 if/elif/else 針對每種狀況寫出處理手段以避開錯誤,不如利用 try,大膽執行程式碼,等到錯誤發生時,將之捕捉當成例外。

這種手法往往可以讓我們開發的更快,錯誤更少。畢竟,錯誤不一定是錯誤,他可能只是個例外。

results matching ""

    No results matching ""