Python Exception (Python 異常處理) – 基礎篇(11)
本篇文章中全面解析了 Python 中的異常處理,包括 try-except 基礎、針對特定異常的處理方法,以及如何靈活運用多個 except、else 和 finally 語句,並通過表格總結了常見異常類型。
Outline
Python 異常處理 – 基本概念
在討論 Python 的異常處理之前,我們首先需要理解什麼是「異常」(Exception)。在 Python 中,異常是一種在執行期間發生的事件,且中斷了當前正在執行的正常流程,在這個時候Python 提供了一種處理異常 ( 事件 ) 的方式,使得程序可以在發生錯誤時恢復並繼續運行。
什麼是異常(Exception)
異常可以由各種原因觸發,例如:
- 嘗試除以零(會引發 ZeroDivisionError)
- 引用不存在的變量(會引發 NameError)
- 打開一個不存在的文件(會引發 FileNotFoundError)
在 Python 中,所有異常都是從一個名為 Exception 的基類派生出來的。
常見的異常類型
Python 內置了多種異常類型,這些異常類型可以涵蓋大多數常見的錯誤情況。一些常見的異常類型包括:
- SyntaxError:語法錯誤
- TypeError:傳入對象類型與要求的不符
- IndexError:索引超出序列範圍
- KeyError:查找字典中不存在的鍵
- ValueError:傳入無效的參數
了解這些常見的異常類型有助於在寫程式時更有效地處理可能發生的錯誤。
異常處理的必要性
在沒有異常處理的情況下,一旦程序遇到錯誤,它將停止執行並顯示錯誤訊息,這可能導致程序的不穩定,甚至崩潰。使用異常處理可以使程序在發生錯誤時仍能繼續運行,並正確的修正錯誤。
在後續文章中,將探討如何在 Python 中使用 try 和 except 語句來處理異常,以及如何針對特定的錯誤進行處理,這將包括具體的範例,以便更好地理解和應用這些概念。
使用 try 和 except 語句
在 Python 中,try 和 except 語句用於處理異常,這是一種基本的錯誤處理機制,能夠幫助程序捕捉並處理在執行過程中可能發生的錯誤,從而避免程序因錯誤而非正常終止。
try 和 except 的基本結構
try 和 except 的使用遵循以下的基本結構:
1 2 3 4 |
try: # 嘗試執行的代碼 except SomeException: # 如果在 try 塊中發生了 SomeException 異常,則執行此塊 |
在這裡,try 塊中的代碼是你想要嘗試執行的代碼,而 except 塊則定義了當 try 塊中的代碼引發了特定異常時應該執行的代碼。
範例:簡單的錯誤捕捉
讓我們看一個簡單的例子來說明這一機制:
1 2 3 4 |
try: result = 10 / 0 except ZeroDivisionError: print("發生了除以零的錯誤") |
在這個例子中,我們嘗試執行一個可能會引發 ZeroDivisionError 的操作(10除以0)。而當這個錯誤發生時,控制流會轉到 except 塊,並打印出錯誤訊息。
處理多種異常
try-except 結構也可以捕捉多種異常類型。這可以通過添加多個 except 塊來實現,每個塊處理一種異常類型:
1 2 3 4 5 6 |
try: # 可能會引發多種異常的代碼 except FirstException: # 處理第一種異常 except SecondException: # 處理第二種異常 |
未指定異常的 except 塊
如果 except 塊後面沒有指定異常類型,它將捕捉 try 塊中發生的任何異常:
1 2 3 4 |
try: # 代碼塊 except: # 處理任何在 try 塊中發生的異常 |
雖然這種方法可以捕捉所有異常,但通常不推薦這麼做,因為它會使錯誤處理變得模糊不清,並可能隱藏一些應該被注意到的問題。
良好的異常處理應該具體且清晰,盡可能具體地捕捉異常,並在 except
塊中明確處理這些異常,這樣可以使代碼更健壯,也更容易調試找到問題並實踐正確的解決方式。
處理特定異常
在 Python 中,處理特定異常是一個重要的概念,它允許我們對不同類型的錯誤進行有針對性的反應,當你明確知道某段代碼可能會引發哪些特定的異常時,你可以為這些特定的異常準備相應的處理邏輯。
如何針對特定錯誤寫 except
語句
在 try 塊後面,我們可以跟上一個或多個 except 塊,每個 except 塊都針對一種特定的異常類型。當 try 塊中的代碼觸發異常時,Python 會檢查每個 except 塊並匹配相應的異常類型。
例如,如果你知道某個操作可能會引發 ValueError 或 TypeError,你可以分別為這兩種異常編寫處理邏輯:
1 2 3 4 5 6 7 8 |
try: # 可能引發 ValueError 或 TypeError 的代碼 except ValueError: # 處理 ValueError print("發生了值錯誤") except TypeError: # 處理 TypeError print("發生了類型錯誤") |
範例:處理特定類型的異常
讓我們來看一個具體的例子。假設我們有一段代碼,該代碼從使用者那裡獲取輸入,並試圖將其轉換為整數:
1 2 3 4 |
try: num = int(input("請輸入一個數字: ")) except ValueError: print("這不是一個有效的數字。請再試一次!") |
在上方例子中,如果使用者輸入的不是數字,int() 函數會引發 ValueError,隨後 except 塊就會捕捉到這個異常並處理它。
處理多個異常
有時,你可能會遇到一段代碼可能會引發多種異常的情況。在這種情況下,你可以通過單個 except 語句來捕捉多個異常,方法是將異常類型放在一個括號內,並用逗號分隔:
1 2 3 4 5 |
try: # 代碼塊 except (ValueError, TypeError): # 同時處理 ValueError 和 TypeError print("發生了值錯誤或類型錯誤") |
自定義錯誤訊息
在處理異常時,有時需要了解更多關於錯誤的信息。這可以通過在 except 語句中訪問異常對象來實現:
1 2 3 4 |
try: # 代碼塊 except ValueError as e: print(f"發生了值錯誤: {e}") |
在這裡,”as e” 語法允許我們訪問與 ValueError 相關的具體錯誤信息。
在Python 異常處理中允許程序對不同類型的錯誤做出更細致和有針對性的反應,並透過精確地捕捉特定異常,你的程序不僅能夠更穩定地運行,而且還能提供更有用的錯誤信息給予使用者。
使用多個 except 語句
在 Python 中,使用多個 except 語句可以讓我們針對不同的異常類型執行不同的錯誤處理代碼,這一種方式來區分處理多種可能在程式執行過程中發生的錯誤。
同時處理多種異常
在一個 try 塊後面,你可以有多個 except 塊,每個 except
塊針對不同的異常。當 try
塊中的代碼發生異常時,Python 會按照它們出現的順序檢查每個 except
塊,並且只執行第一個匹配異常類型的 except
塊。
範例:使用多個 except 塊
考慮以下代碼片段,它嘗試執行幾個可能引發不同錯誤的操作:
1 2 3 4 5 6 7 8 9 10 11 12 |
try: # 這裡的代碼可能引發多種異常 # 例如:除以零、類型錯誤等 except ZeroDivisionError: # 處理除以零的錯誤 print("不能除以零") except TypeError: # 處理類型錯誤 print("類型錯誤發生了") except Exception as e: # 捕捉其他所有異常 print(f"發生了其他錯誤:{e}") |
在上方例子中,我們首先捕捉 ZeroDivisionError,然後是 TypeError。如果發生了這些類型的錯誤之一,相關的 except
塊將被執行。如果發生了任何其他類型的異常,最後一個 except 塊(它捕捉所有的 Exception)將被執行。
注意事項
- 順序重要:except 塊應該從最具體的異常到最通用的異常排列。這是因為一旦匹配到一個
except
塊,後續的except
塊就不會再被檢查。 - 避免過度捕捉:雖然使用一個捕捉所有異常的 except 語句(即捕捉 Exception)看起來是一個容易的解決方案,但它可能會隱藏一些不應該被忽視的錯誤。因此,最好是儘可能具體地捕捉異常。
使用多個 except 語句,你可以為你的應用程式提供更靈活且更精確的錯誤處理能力,這不僅可以幫助你的程式更好地應對不同的錯誤情況,還可以提高程式的穩定性和可靠性。
使用 else 和 finally 語句
在 Python 的錯誤處理機制中,else 和 finally 語句提供了額外的靈活性。這兩個語句可以和 try 及 except 語句一起使用,以處理不同的程序執行情況。
else 語句的作用
else 塊在 try 塊中的代碼成功執行且沒有觸發任何異常時執行。它通常用於執行一些只有在 try 塊成功完成時才需要執行的代碼。
範例:
1 2 3 4 5 6 |
try: # 嘗試執行的代碼,可能會引發異常 except SomeException: # 如果發生 SomeException 異常,則執行此塊 else: # 如果 try 塊成功,則執行此塊 |
在這個例子中,如果 try 塊中的代碼成功執行且沒有引發 SomeException,則會執行 else 塊中的代碼。
finally 語句的作用
finally 塊無論是否觸發異常都會執行。這對於進行一些清理工作,如關閉文件或釋放資源等,非常有用。
1 2 3 4 5 6 |
try: # 嘗試執行的代碼,可能會引發異常 except SomeException: # 如果發生 SomeException 異常,則執行此塊 finally: # 不論是否發生異常,都會執行此塊 |
無論 try 塊是否成功,或是否捕捉到異常,finally 塊總是會被執行。
整合 else 和 finally
在實際的應用中,else 和 finally 可以與 try 和 except 語句一起使用,形成一個完整的錯誤處理機制。
完整範例:
1 2 3 4 5 6 7 8 9 10 |
try: # 嘗試執行的代碼 except SomeException: # 處理特定異常 except AnotherException: # 處理另一種異常 else: # 如果沒有異常發生,執行此塊 finally: # 無論如何都會執行的代碼 |
這樣的結構使得程序能夠更全面地處理各種可能的執行情況,並確保重要的清理或結尾工作總是被完成。
使用這些語句可以讓你的錯誤處理邏輯更加精準和全面,並且確保了無論程序執行的情況如何,一些必要的清理和結尾工作都能被正確執行。在實際建立錯誤處理策略時,合理地利用這些工具可以大大提升程序的可靠性。
參考資料
常見的異常,幫各位整理成表格
異常類型 | 描述 |
---|---|
Exception | 所有內置非系統退出異常的基類。 |
ArithmeticError | 所有數值計算錯誤的基類。 |
BufferError | 與緩衝區相關的操作錯誤。 |
LookupError | 當索引或鍵查找失敗時引發的基類。 |
AssertionError | 斷言語句(assert )失敗時引發。 |
AttributeError | 物件沒有這個屬性時引發。 |
EOFError | input() 遇到文件結束條件(EOF)時引發。 |
FloatingPointError | 浮點計算錯誤時引發。 |
GeneratorExit | 當生成器(generator)或協程(coroutine)被關閉時引發,不應被捕捉。 |
ImportError | 導入模塊/物件失敗時引發。 |
ModuleNotFoundError | 找不到模塊時引發,繼承自 ImportError 。 |
IndexError | 索引不在序列的範圍內時引發。 |
KeyError | 字典中找不到鍵時引發。 |
KeyboardInterrupt | 用戶中斷執行(通常是輸入^C)時引發。 |
MemoryError | 操作耗盡記憶體時引發。 |
NameError | 找不到本地或全域名稱時引發。 |
NotImplementedError | 在用戶定義的基類中,當子類沒有實現基類中的方法時引發。 |
OSError | 操作系統不能執行的操作時引發,有多個子類。 |
OverflowError | 數值運算超出最大限制時引發。 |
RecursionError | 解釋器檢測到過深的遞迴時引發,繼承自 RuntimeError 。 |
ReferenceError | 嘗試訪問已經被垃圾回收機制回收的弱引用時引發。 |
RuntimeError | 發生無法歸類到其他類別的錯誤時引發。 |
StopIteration | 迭代器沒有更多的值時引發。 |
SyntaxError | 語法錯誤時引發。 |
IndentationError | 縮排錯誤時引發,繼承自 SyntaxError 。 |
TabError | Tab 和空格混用時引發,繼承自 IndentationError 。 |
SystemError | 解釋器系統發生錯誤時引發。 |
SystemExit | Python 解釋器請求退出時引發。 |
TypeError | 操作或函數應用於不適當類型的物件時引發。 |
UnboundLocalError | 訪問未初始化的本地變數時引發,繼承自 NameError 。 |
UnicodeError | Unicode 相關的錯誤時引發,有多個子類。 |