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

更新於 發佈於 閱讀時間約 16 分鐘

不管你是程式的新手或老手,不管你是不是第一天寫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 <module>
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 <module>
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 <module>
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 <module>
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 <module>
print_city(2)
File "C:\Users\wjweng\PycharmProjects\marathon_python\Day33\main.py", line 4, in print_city
raise IndexError("索引值超出自訂範圍")
IndexError: 索引值超出自訂範圍

定義了異常事件後,我們同樣可以使用上面提過的所有異常處理程序來處理自定義的異常事件,這裡就不再多重覆一次。

總結

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

程式範例

https://github.com/wjweng/marathon_python/tree/master/Day33

留言
avatar-img
留言分享你的想法!
avatar-img
Wei-Jie Weng的沙龍
48會員
36內容數
Wei-Jie Weng的沙龍的其他內容
2022/07/13
對於程式的初學者而言,理解程式的流程、迴圈的進行、或是變數的變化會需要一定程度將程式在腦中進行運算的能力,要一段時間熟悉與適應,尤其是當程式執行的結果不如預期時,往往是計算的過程和自己所想像的不同,這時又更難靠自己的能力找出錯誤。因此,這邊要介紹的這個工具可以將程式執行的過程逐行將變數的變化視覺化地
Thumbnail
2022/07/13
對於程式的初學者而言,理解程式的流程、迴圈的進行、或是變數的變化會需要一定程度將程式在腦中進行運算的能力,要一段時間熟悉與適應,尤其是當程式執行的結果不如預期時,往往是計算的過程和自己所想像的不同,這時又更難靠自己的能力找出錯誤。因此,這邊要介紹的這個工具可以將程式執行的過程逐行將變數的變化視覺化地
Thumbnail
2022/07/13
在上一節介紹了 JSON 資料的基本架構後,我們將改寫並擴充密碼產生器程式,讓它能夠藉由 JSON 的資料結構完成帳密搜尋的功能。
Thumbnail
2022/07/13
在上一節介紹了 JSON 資料的基本架構後,我們將改寫並擴充密碼產生器程式,讓它能夠藉由 JSON 的資料結構完成帳密搜尋的功能。
Thumbnail
2022/06/23
JSON的全名叫JavaScript Object Notation,是由Douglas Crockford所設計的一種資料格式,最初應用在JavaScript程式語言中,做為一種資料交換的格式,而後被廣泛運用在Web開發與NoSQL資料庫,現今已成為一種重要的資料格式。
Thumbnail
2022/06/23
JSON的全名叫JavaScript Object Notation,是由Douglas Crockford所設計的一種資料格式,最初應用在JavaScript程式語言中,做為一種資料交換的格式,而後被廣泛運用在Web開發與NoSQL資料庫,現今已成為一種重要的資料格式。
Thumbnail
看更多
你可能也想看
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
在讀取檔案時,最怕路徑的問題,常常會有路徑錯誤造成的異常報錯。 為了避免諸如此類的問題發生,明白程式的當前目錄與檔案的路徑是很重要的。 可以利用os 模組是 Python 中的一個標準庫,提供了許多與操作系統的功能。 以下是一些常用的 os 模組基本操作及其範例: 1. os.getcwd
Thumbnail
在讀取檔案時,最怕路徑的問題,常常會有路徑錯誤造成的異常報錯。 為了避免諸如此類的問題發生,明白程式的當前目錄與檔案的路徑是很重要的。 可以利用os 模組是 Python 中的一個標準庫,提供了許多與操作系統的功能。 以下是一些常用的 os 模組基本操作及其範例: 1. os.getcwd
Thumbnail
例外處理是Python中的重要概念,用於控制並處理程序異常,防止程序崩潰和數據損失。它包括try, except, else和finally等語法結構,可用於對特定錯誤進行處理,或主動觸發和自定義異常。
Thumbnail
例外處理是Python中的重要概念,用於控制並處理程序異常,防止程序崩潰和數據損失。它包括try, except, else和finally等語法結構,可用於對特定錯誤進行處理,或主動觸發和自定義異常。
Thumbnail
本文介紹Python程式設計中處理異常的try, except, else, finally語句,並提供程式範例來更深刻理解使用方法。
Thumbnail
本文介紹Python程式設計中處理異常的try, except, else, finally語句,並提供程式範例來更深刻理解使用方法。
Thumbnail
例外處理 在Python中,try 和 except 是用來處理異常的關鍵字。它們讓你能夠在代碼中檢測和處理可能引發異常的情況,以確保程序在遇到問題時不會崩潰,而是能夠優雅地處理錯誤情況。 基本用法,以下是 try 和 except 的基本用法: try: # 可能引發異常的代碼 excep
Thumbnail
例外處理 在Python中,try 和 except 是用來處理異常的關鍵字。它們讓你能夠在代碼中檢測和處理可能引發異常的情況,以確保程序在遇到問題時不會崩潰,而是能夠優雅地處理錯誤情況。 基本用法,以下是 try 和 except 的基本用法: try: # 可能引發異常的代碼 excep
Thumbnail
本篇文章介紹了在Python中的錯誤處理機制。錯誤處理在程式設計中是一個重要環節,能夠有效處理可能發生的錯誤。示範了如何捕捉錯誤並根據不同錯誤類型進行處理或提示。此外,還介紹了指定特定錯誤類型和捕捉所有錯誤的方法。透過學習這些錯誤處理的技巧,讀者可以更好地避免程式崩潰,提供友善的使用者體驗。
Thumbnail
本篇文章介紹了在Python中的錯誤處理機制。錯誤處理在程式設計中是一個重要環節,能夠有效處理可能發生的錯誤。示範了如何捕捉錯誤並根據不同錯誤類型進行處理或提示。此外,還介紹了指定特定錯誤類型和捕捉所有錯誤的方法。透過學習這些錯誤處理的技巧,讀者可以更好地避免程式崩潰,提供友善的使用者體驗。
Thumbnail
  程式在執行的過程中難免會遇到意外的狀況發生,這時該怎麼辦呢?現實生活中我們可能就會去保保險,那麼程式怎麼辦?有一個例外處理try...catch可以幫我們解決這個問題,甚至還可以使用throw可以丟出例外,例外處理部分是可以透過程式的規劃來了解是哪邊出問題的哦!怎麼說呢?我們來看一下例子:
Thumbnail
  程式在執行的過程中難免會遇到意外的狀況發生,這時該怎麼辦呢?現實生活中我們可能就會去保保險,那麼程式怎麼辦?有一個例外處理try...catch可以幫我們解決這個問題,甚至還可以使用throw可以丟出例外,例外處理部分是可以透過程式的規劃來了解是哪邊出問題的哦!怎麼說呢?我們來看一下例子:
Thumbnail
不管你是程式的新手或老手,不管你是不是第一天寫Python程式,在編譯或執行時絕對有出現程式錯誤或異常的時候,也就是俗稱的「bug」,這對於程式編譯人員是好事,你可以在程式撰寫階段就事先排除這些異常,或是加上捕捉異常的程式區段以及處理程序,讓程式即使出現異常也可以繼續執行。
Thumbnail
不管你是程式的新手或老手,不管你是不是第一天寫Python程式,在編譯或執行時絕對有出現程式錯誤或異常的時候,也就是俗稱的「bug」,這對於程式編譯人員是好事,你可以在程式撰寫階段就事先排除這些異常,或是加上捕捉異常的程式區段以及處理程序,讓程式即使出現異常也可以繼續執行。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News