不間斷 Python 挑戰 Day 33 - 異常處理

閱讀時間約 15 分鐘
不管你是程式的新手或老手,不管你是不是第一天寫Python程式,在編譯或執行時絕對有出現程式錯誤或異常的時候,也就是俗稱的「bug」,這對於程式編譯人員是好事,你可以在程式撰寫階段就事先排除這些異常,或是加上捕捉異常的程式區段以及處理程序,讓程式即使出現異常也可以繼續執行。因此,首先我們可以先來看一下常見的異常事件有哪些,相信寫過Python程式的人,很多都已經遇過了。

常見異常事件

AttributionError:物件沒有這個屬性
Exception:通用型的錯誤事件
FileNotFoundError:找不到open()開啟的檔案
FloatingPointError:浮點計算錯誤
ImportError:匯入模組或物件失敗
IndentationError:縮排錯誤
IndexError:索引超出範圍
IOError:輸入/輸出操作失敗
KeyError:不存在這個鍵
MemoryError:記憶體溢位
NameError:物件未宣告
OverflowError:數值運算超出最大限制
SyntaxError:語法錯誤
SystemError:直譯器的系統錯誤
TypeError:資料型別錯誤
ValueError:傳入無效的參數
ZeroDivisionError:除數為0
以下我們來舉一些常見的異常事件,看一下Python的Traceback會告訴我們什麼訊息。

FileNotFoundError

嘗試開啟一個程式路徑底下找不到的檔案會出現FileNotFoundError。
# FileNotFoundError
with open("file.txt", "r") as file:
  file.read()
這時Python的Traceback會列出異常報告,告訴我們錯誤出現在哪個檔案的第幾行,以及錯誤的類型和說明。如以下,報告中明確指出了Python直譯器發現在「main.py」的「with open("file.txt", "r") as file:」這一行出現了錯誤,錯誤的類型是「FileNotFoundError」,原因是「No such file or directory: 'file.txt'」,並沒有存在「file.txt」這個檔案讓程式開啟。
Traceback (most recent call last):
File "C:\Users\wjweng\PycharmProjects\marathon_python\Day33\main.py", line 2, in
with open("file.txt", "r") as file:
FileNotFoundError: [Errno 2] No such file or directory: 'file.txt'

KeyError

嘗試透過字典中不存在的鍵來取得值會出現KeyError。
# KeyError
dictionary = {"台北市": 100}
value = dictionary["新北市"]
dictionary這個字典僅存在"台北市": 100這樣一組鍵值對,當我們試圖使用不存在的"新北市"做為鍵來取值便會出現錯誤,Traceback訊息如下:
Traceback (most recent call last):
  File "C:\Users\wjweng\PycharmProjects\marathon_python\Day33\main.py", line 2, in 
    value = dictionary["新北市"]
KeyError: '新北市'

IndexError

使用超出串列範圍的索引值來存取串列內容會出現IndexError。
# IndexError
city_list = ["台北市", "新北市", "台中市"]
city = city_list[3]
串列city_list存在三個元素,索引值範圍為0~2,當使用3做為索引來取用串列值會出現錯誤,Traceback訊息如下:
Traceback (most recent call last):
  File "C:\Users\wjweng\PycharmProjects\marathon_python\Day33\main.py", line 2, in 
    city = city_list[3]
IndexError: list index out of range

TypeError

使用非預期的資料型別來做操作會出現TypeError。
# TypeError
text = "大家好"
print(text + 1)
上述程式使用字串型別的變數text來做加法運算,因兩者資料型別不一致而無法執行,Traceback訊息如下:
Traceback (most recent call last):
  File "C:\Users\wjweng\PycharmProjects\marathon_python\Day33\main.py", line 2, in 
    print(text + 1)
TypeError: can only concatenate str (not "int") to str

異常處理程序

try - except

try - except語句為最基本的異常處理程序,try語句區塊中為可能需要捕捉異常情況的指令,except語句區塊為當異常情況發生時的處理方式,語法如下:
try:
  可能需要捕捉異常情況的指令
except:
  異常情況發生時的處理方式
如以下範例,我們將前述IndexError的範例程式放入try語塊,並在except中捕捉IndexError,當出現這項錯誤時,會執行except語塊中的內容,避免程式因錯誤而終止。
def print_city(index):
  city_list = ["台北市", "新北市", "台中市"]

  try:
    city = city_list[index]
  except IndexError:
    print("索引值超出範圍!")

print_city(3)
執行結果:
索引值超出範圍!

try - except - else

此語法在try - except語句下又擴充了else指令,當try語塊中的指令執行正常時,便會執行else語塊中的內容,擴充後的語法如下:
try:
  可能需要捕捉異常情況的指令
except:
  異常情況發生時的處理方式
else:
  指令正確執行時的處理方式
以下程式中,0可以做為索引值來取得city_list的元素,因此程式會跳過except區塊,直接執行else區塊的內容。
def print_city(index):
  city_list = ["台北市", "新北市", "台中市"]

  try:
    city = city_list[index]
  except IndexError:
    print("索引值超出範圍")
  else:
    print(city)

print_city(0)
執行結果:
台北市

try - except - else - finally

finally指令放在異常處理程序的最後方,區塊內放置無論是否有異常情況發生都會執行的內容,完整的語法如下:
try:
  可能需要捕捉異常情況的指令
except:
  異常情況發生時的處理方式
else:
  指令正確執行時的處理方式
finally:
  程式正常或異常皆會執行的指令
以下範例除了增加了finally區塊外,其餘同上述程式,執行後會多印出finally區塊的內容。
def print_city(index):
  city_list = ["台北市", "新北市", "台中市"]

  try:
    city = city_list[index]
  except IndexError:
    print("索引值超出範圍")
  else:
    print(city)
  finally:
    print("執行完畢!")

print_city(0)
執行結果:
台北市
執行完畢!

捕捉多個異常

若預期的錯誤可能不只一種,可以設計多個except區塊捕捉不同的異常,或是在一個except區塊內來捕捉多個異常。
  • 使用多個except區塊捕捉不同的異常,語法如下:
try:
  可能需要捕捉異常情況的指令
except 異常事件1:
  異常事件1發生時的處理方式
except 異常事件2:
  異常事件2發生時的處理方式
......
延續之前的範例,除了原有的IndexError以外,新增捕捉TypeError,當print_city()輸入的參數為3及"a"時,分別跳出不同的錯誤訊息。
def print_city(index):
  city_list = ["台北市", "新北市", "台中市"]

  try:
    city = city_list[index]
  except IndexError:
    print("索引值超出範圍!")
  except TypeError:
    print("型別錯誤!")
  else:
    print(city)
  finally:
    print("執行完畢!")

print_city(3)
print_city("a")
執行結果:
索引值超出範圍!
執行完畢!
型別錯誤!
執行完畢!
  • 使用一個except區塊捕捉多個異常,語法如下:
try:
  可能需要捕捉異常情況的指令
except (異常事件1, 異常事件2, ......):
  異常事件發生時的處理方式
重新設計上個範例,將IndexError及TypeError放在同一個except區塊裡面,但此種寫法便無法區隔是哪一種異常事件導致錯誤發生。
def print_city(index):
  city_list = ["台北市", "新北市", "台中市"]

  try:
    city = city_list[index]
  except (IndexError, TypeError):
    print("索引值超出範圍 或 型別錯誤!")
  else:
    print(city)
  finally:
    print("執行完畢!")

print_city(3)
print_city("a")
執行結果:
索引值超出範圍 或 型別錯誤!
執行完畢!
索引值超出範圍 或 型別錯誤!
執行完畢!

使用內建錯誤訊息

針對上述無法區分異常事件的情況,我們可以導出Python內建的錯誤訊息,來協助分辨錯誤的類型,語法如下:
try:
  可能需要捕捉異常情況的指令
except (異常事件1, 異常事件2, ......) as error_message:
  異常事件發生時的處理方式
改良上述程式,使用error_message將錯誤訊息儲存起來,就可以在發生IndexError時,印出「list index out of range」,而在發生TypeError時,印出「list indices must be integers or slices, not str」等不同的錯誤訊息。
def print_city(index):
  city_list = ["台北市", "新北市", "台中市"]

  try:
    city = city_list[index]
  except (IndexError, TypeError) as error_message:
    print(f"{error_message}")
  else:
    print(city)
  finally:
    print("執行完畢!")

print_city(3)
print_city("a")
執行結果:
list index out of range
執行完畢!
list indices must be integers or slices, not str
執行完畢!

自定義異常

除了讓Python直譯器自行判斷異常外,我們也可以使用raise語法自行定義異常事件,這個異常事件可以是Python判斷為正常的情況。如以下的程式碼中,我們把索引值大於1就定義為異常,但實際上索引值為2對於Python而言也是合理的。
def print_city(index):
  city_list = ["台北市", "新北市", "台中市"]

  if index > 1:
    raise IndexError("索引值超出範圍")

print_city(3)
執行後,Python會根據我們所自定義的異常事件來丟出Traceback訊息。
Traceback (most recent call last):
  File "C:\Users\wjweng\PycharmProjects\marathon_python\Day33\main.py", line 6, in 
    print_city(2)
  File "C:\Users\wjweng\PycharmProjects\marathon_python\Day33\main.py", line 4, in print_city
    raise IndexError("索引值超出自訂範圍")
IndexError: 索引值超出自訂範圍
定義了異常事件後,我們同樣可以使用上面提過的所有異常處理程序來處理自定義的異常事件,這裡就不再多重覆一次。

總結

俗話說「怕熱就不要進廚房」,對於寫程式的人來說,沒有遇過或解過bug的就不算真正寫過程式,重要的是如何培養debug的能力,以及如何對於可能預期的異常事件做出對應的預防處理。本篇算是這系列文章首次對於異常事件做初步的介紹,除了列出一些初學者常遇到的異常事件外,也說明了Python對於異常事件的處理程序,讓我們在寫作程式時,能減少一些讓程式異常終止的機會,增加一些容錯的能力。

程式範例

為什麼會看到廣告
avatar-img
47會員
36內容數
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
Wei-Jie Weng的沙龍 的其他內容
在先前的文章中,我們曾經實做過文字介面版本的密碼產生器,這篇文章中,我們將添加新的功能,包括記錄密碼使用場域的名稱、網址、帳號等,並能夠將以上記錄存檔,當然最重要的是將它轉換成友善的圖形介面。
繼上一篇文章介紹了多種tkinter的視窗元件後,這篇我們再來討論三種視窗元件的配置方法以及優缺點,以適當移動各個元件到視窗中指定的位置,讓整個視窗版面的配置看起來更合理且美觀。
之前的文章中介紹過了Turtle Graphics,它是架構於tkinter模組之上以實現基本圖形介面的繪圖模組,這篇文章就來說明tkinter模組常用元件(widget)的基本用法,以及如何用它來設計出一個具有圖形使用者介面(Graphical User Interface, GUI)的程式。
在上一篇的文章中,我們提到關於開啟CSV文件的方式,從單純的當作純文字文件開啟,到引入Python內建的csv模組對CSV類型的檔案做基本的讀寫操作,在這篇文章中,我們將再進一步使用Pandas這套強大的工具,來簡化CSV文件處理的流程。
CSV全名為Comma-Separated Values,中文稱為逗號分隔值,也可稱為字元分隔值,因為分隔字元也可以不是逗號。它以純文字的形式儲存表格資料,同一列的資料以逗號或其它符號分隔成不同欄位,每一列的資料間以換行符號分隔。網路上很多資料的格式都是以CSV檔案呈現,例如交通部中央氣象局的觀測資
到目前為止,我們都還是在附檔名為.py的Python檔案執行程式碼,當程式需要與外部的檔案互動,例如讀取文字、表格、或是影像來做分析,或是把程式執行的結果儲存下來,就需要能夠存取外部的檔案。例如,在上一節中,當貪食蛇遊戲結束之後,隨著程式停止執行,該次的分數也就被丟棄,若能將分數記錄下來,下次遊戲開
在先前的文章中,我們曾經實做過文字介面版本的密碼產生器,這篇文章中,我們將添加新的功能,包括記錄密碼使用場域的名稱、網址、帳號等,並能夠將以上記錄存檔,當然最重要的是將它轉換成友善的圖形介面。
繼上一篇文章介紹了多種tkinter的視窗元件後,這篇我們再來討論三種視窗元件的配置方法以及優缺點,以適當移動各個元件到視窗中指定的位置,讓整個視窗版面的配置看起來更合理且美觀。
之前的文章中介紹過了Turtle Graphics,它是架構於tkinter模組之上以實現基本圖形介面的繪圖模組,這篇文章就來說明tkinter模組常用元件(widget)的基本用法,以及如何用它來設計出一個具有圖形使用者介面(Graphical User Interface, GUI)的程式。
在上一篇的文章中,我們提到關於開啟CSV文件的方式,從單純的當作純文字文件開啟,到引入Python內建的csv模組對CSV類型的檔案做基本的讀寫操作,在這篇文章中,我們將再進一步使用Pandas這套強大的工具,來簡化CSV文件處理的流程。
CSV全名為Comma-Separated Values,中文稱為逗號分隔值,也可稱為字元分隔值,因為分隔字元也可以不是逗號。它以純文字的形式儲存表格資料,同一列的資料以逗號或其它符號分隔成不同欄位,每一列的資料間以換行符號分隔。網路上很多資料的格式都是以CSV檔案呈現,例如交通部中央氣象局的觀測資
到目前為止,我們都還是在附檔名為.py的Python檔案執行程式碼,當程式需要與外部的檔案互動,例如讀取文字、表格、或是影像來做分析,或是把程式執行的結果儲存下來,就需要能夠存取外部的檔案。例如,在上一節中,當貪食蛇遊戲結束之後,隨著程式停止執行,該次的分數也就被丟棄,若能將分數記錄下來,下次遊戲開
你可能也想看
Google News 追蹤
Thumbnail
在 Python 中,你可以使用 raise 關鍵字手動觸發錯誤。這對於測試異常處理或在特定情況下停止程式執行非常有用。 本文主說明在影像處理中常見的異常情況,展示如何使用 raise 來觸發不同類型的錯誤。 1. 檔案不存在 (FileNotFoundError) 在影像處理中,如果要讀取
在處理數據時,最可能會遇到數據中含有None的時候,若沒有處理就進行運算就會造成程式崩潰或者報錯 數據中含有None input_list = [(42, 292), (28, 296), (999, 92), (993, 46), (219, 4), (279, 2), (None, None
在檢查列表中含有tuple的座標點時,若要給其他演算法做運算時若有其中有tuple有空值時,就會報錯。 本文主要介紹兩種方法可以檢查是否有空值 程式範例1 positon_list =[(42,123),(None,None),(22,11)] for cord in positon_lis
Thumbnail
在讀取檔案時,最怕路徑的問題,常常會有路徑錯誤造成的異常報錯。 為了避免諸如此類的問題發生,明白程式的當前目錄與檔案的路徑是很重要的。 可以利用os 模組是 Python 中的一個標準庫,提供了許多與操作系統的功能。 以下是一些常用的 os 模組基本操作及其範例: 1. os.getcwd
Thumbnail
例外處理是Python中的重要概念,用於控制並處理程序異常,防止程序崩潰和數據損失。它包括try, except, else和finally等語法結構,可用於對特定錯誤進行處理,或主動觸發和自定義異常。
Thumbnail
在實務上,若Python報錯時,若引入的套件越多伴隨的異常訊息會變得越來越複雜,看到一推密密麻麻的內容時,很多時候都想直接跳過。 本文將利用Traceback來讓異常訊息變得更好理解。
Thumbnail
當我們在做很多處理時,結果可能會是List包住一些數值,例如找輪廓或連通域分析時,沒有剛好的特徵可能就會有List含(空值得)形式出現。 為了避免報錯,我們就要額外先做一些處理,先做判斷是否有值在往下一個階段。 all 和 any 是 Python 中用於檢查可迭代物件(如清單、元組、集合等)
Thumbnail
在程式中,了解資料型態是相當重要的。 為什麽? 因為許多error,常常都是因為資料型態不正確所導致的。 舉個例子,在python中: a = 1 + 2 print(a) 結果就是3 a = = "1"+"2" print(a) 結果就是12 是不是差很多? 所以今天我來介
Thumbnail
本文介紹Python程式設計中處理異常的try, except, else, finally語句,並提供程式範例來更深刻理解使用方法。
Thumbnail
我們在處理音檔時常常會使用到 [soundfile](https://pypi.org/project/soundfile/) 這套工具, 當我們試圖讀取檔案時卻發生了這樣的錯誤訊息… TypeError: Not allowed for existing files (except 'RAW')
Thumbnail
在 Python 中,你可以使用 raise 關鍵字手動觸發錯誤。這對於測試異常處理或在特定情況下停止程式執行非常有用。 本文主說明在影像處理中常見的異常情況,展示如何使用 raise 來觸發不同類型的錯誤。 1. 檔案不存在 (FileNotFoundError) 在影像處理中,如果要讀取
在處理數據時,最可能會遇到數據中含有None的時候,若沒有處理就進行運算就會造成程式崩潰或者報錯 數據中含有None input_list = [(42, 292), (28, 296), (999, 92), (993, 46), (219, 4), (279, 2), (None, None
在檢查列表中含有tuple的座標點時,若要給其他演算法做運算時若有其中有tuple有空值時,就會報錯。 本文主要介紹兩種方法可以檢查是否有空值 程式範例1 positon_list =[(42,123),(None,None),(22,11)] for cord in positon_lis
Thumbnail
在讀取檔案時,最怕路徑的問題,常常會有路徑錯誤造成的異常報錯。 為了避免諸如此類的問題發生,明白程式的當前目錄與檔案的路徑是很重要的。 可以利用os 模組是 Python 中的一個標準庫,提供了許多與操作系統的功能。 以下是一些常用的 os 模組基本操作及其範例: 1. os.getcwd
Thumbnail
例外處理是Python中的重要概念,用於控制並處理程序異常,防止程序崩潰和數據損失。它包括try, except, else和finally等語法結構,可用於對特定錯誤進行處理,或主動觸發和自定義異常。
Thumbnail
在實務上,若Python報錯時,若引入的套件越多伴隨的異常訊息會變得越來越複雜,看到一推密密麻麻的內容時,很多時候都想直接跳過。 本文將利用Traceback來讓異常訊息變得更好理解。
Thumbnail
當我們在做很多處理時,結果可能會是List包住一些數值,例如找輪廓或連通域分析時,沒有剛好的特徵可能就會有List含(空值得)形式出現。 為了避免報錯,我們就要額外先做一些處理,先做判斷是否有值在往下一個階段。 all 和 any 是 Python 中用於檢查可迭代物件(如清單、元組、集合等)
Thumbnail
在程式中,了解資料型態是相當重要的。 為什麽? 因為許多error,常常都是因為資料型態不正確所導致的。 舉個例子,在python中: a = 1 + 2 print(a) 結果就是3 a = = "1"+"2" print(a) 結果就是12 是不是差很多? 所以今天我來介
Thumbnail
本文介紹Python程式設計中處理異常的try, except, else, finally語句,並提供程式範例來更深刻理解使用方法。
Thumbnail
我們在處理音檔時常常會使用到 [soundfile](https://pypi.org/project/soundfile/) 這套工具, 當我們試圖讀取檔案時卻發生了這樣的錯誤訊息… TypeError: Not allowed for existing files (except 'RAW')