Contents

如何在 Python 中建立自訂異常

Python 內建的異常類別無法解決程式碼中可能出現的某些錯誤情況。在這種情況下,您需要建立自訂異常來有效處理這些錯誤。

在 Python 等程式語言領域,可以創建自訂的異常類,這些異常類別可能在特定錯誤場景的實例中引發。透過利用這些客製化的異常類型,人們可以有效地解決程式碼庫中更精確和詳細的問題,最終提高程式碼組織和可讀性方面的清晰度和易於維護性。

為什麼需要自訂異常?

/bc/images/own-you-error.jpg

在軟體程式的發展過程中,由於原始程式碼的變更、與附加模組或程式庫的介面或與遠端應用程式的合作,可能會出現不可預見的複雜情況。對此類違規行為的有效管理對於確保系統能夠從這些挫折中恢復或以平穩的方式執行終止程序至關重要。

Python 提供了一系列內建異常 類,這些類別涵蓋了 ValueError 、 TypeError 、 FileNotFoundError 等錯誤。雖然這些內建異常很好地滿足了它們的目的,但它們有時只能準確地表示應用程式中可能發生的錯誤。

客製化自訂異常可以更精確地滿足應用程式中的特定需求,為可能遇到此類程式碼的開發人員提供有價值的見解。

如何定義自訂異常

若要建立自訂異常,請定義一個繼承自 Exception 類別 的 Python 類別。 Exception 類別提供了處理異常所需的基本功能,並且您可以根據您的特定需求進行自訂以新增功能。

在開發個人化異常類別時,重要的是要保持簡單性,同時結合保留錯誤詳細資訊的關鍵功能。異常管理者隨後可以利用這些特徵來有效地解決錯誤。

這是一個自訂異常類,MyCustomError:

 class MyCustomError(Exception):
    def __init__(self, message=None):
        self.message = message
        super().__init__(message)

在其初始化過程中,該特定類別允許有條件地包含訊息參數。利用「super」關鍵字,它有效地呼叫其祖先 Exception 類別的建構函數,該類別是異常處理協定中的關鍵元件。

如何引發自訂異常

事實上,為了引發障礙並產生我們自訂的異常類別的實例,您可以將「raise」關鍵字與自訂異常類型的範例結合使用,為其提供封裝問題本質的訊息:

 if True:
    raise MyCustomError("A Custom Error Was Raised!!!.")

人們也可以選擇提出一個例外,而不提供任何論據,

 if True:
    raise MyCustomError # shorthand

兩種格式同樣適合建立自訂錯誤訊息。

/bc/images/raised-custom-error.jpg

如何處理自訂異常

處理自訂異常時,必須採用與處理標準異常時類似的策略。這涉及利用 try-except-finally 區塊來捕獲這些異常情況並相應地執行適當的補救措施。透過這樣做,我們可以有效地管理程式碼執行期間可能出現的意外情況並從中復原。

 try:
    print("Hello, You're learning how to All Things N Custom Errors")
    raise MyCustomError("Opps, Something Went Wrong!!!.")
except MyCustomError as err:
    print(f"Error: {err}")
finally:
    print("Done Handling Custom Error")

透過這種方式,人們就有能力應對可能出現的各種可能出現的異常情況。

/bc/images/handling-custom-error.jpg

如果在執行 try 區塊時出現異常,其對應的 except 區塊可以捕獲並管理它。但是,如果沒有合適的 except 區塊來處理異常,則任何存在的 finally 區塊都會執行,導致異常再次引發。使用finally區塊的主要目的應該是執行強制性的清理操作,無論是否發生異常。

 try:
    raise KeyboardInterrupt
except MyCustomError as err:
    print(f"Error: {err}")
finally:
    print("Did not Handle the KeyboardInterrupt Error. \
Can Only Handle MyCustomError")

在這種情況下,鍵盤會發生中斷,但是,包含的「例外」部分僅限於處理「MyCustomError」實例。因此,當執行“finally”子句時,先前未確認的異常隨後將被恢復。

/bc/images/re-raise-unhandled-exception.jpg

繼承自訂錯誤類別

物件導向程式設計 (OOP) 的原理使人們不僅可以將繼承擴展到標準資料類型,還可以擴展到個人化異常類別,就像典型的類別一樣。透過這種技術,可以建立異常類,以更清楚地了解錯誤背後的情況。這種方法允許在程序的各個階段處理錯誤,並加深對問題原因的理解。

為了確保對 Web 應用程式中的外部 API 整合中的各種錯誤場景進行一致處理,建議透過建立稱為 BaseAPIException 的特定異常類別來建立標準化方法。

 class BaseAPIException(Exception):
    """Base class for API-related exceptions."""
    def __init__(self, message):
        super().__init__(message)
        self.message = message

為了擴展自訂異常類別的功能,可以建立從父類別派生的子類別。此過程允許創建專門的異常,這些異常與其父類共享共同的屬性和行為,同時還擁有針對特定情況定制的獨特特徵。

 class APINotFoundError(BaseAPIException):
    """Raised when the requested resource is not found in the API."""
    pass

class APIAuthenticationError(BaseAPIException):
    """Raised when there's an issue with authentication to the API."""
    pass

class APIRateLimitExceeded(BaseAPIException):
    """Raised when the rate limit for API requests is exceeded."""
    pass

實作 Web 應用程式時,必須透過引發和擷取特定的自訂異常來處理 API 呼叫期間可能出現的任何潛在錯誤。透過這樣做,您可以使用針對每種情況量身定制的明確定義的程式邏輯來有效地管理這些情況。

 def request_api():
    try:
        # Simulate an API error for demonstration purposes
        raise APINotFoundError("Requested resource not found.")
    except APINotFoundError as err:
        # Log or handle the 'Not Found' error case
        print(f"API Not Found Error: {err}")
    except APIAuthenticationError:
        # Take appropriate actions for authentication error
        print(f"API Authentication Error: {err}")
    except APIRateLimitExceeded:
        # Handle the rate limit exceeded scenario
        print(f"API Rate Limit Exceeded: {err}")
    except BaseAPIException:
        # Handle other unknown API exceptions
        print(f"Unknown API Exception: {err}") 

最終的 except 子句負責捕獲父類別中可能出現的任何異常,充當與應用程式介面 (API) 相關的任何不可預見問題的全面錯誤處理程序。

/bc/images/inheriting-custom-exception.jpg

當繼承自訂異常類別時,他們能夠有效地管理 API 中的錯誤。這種方法可以將錯誤處理與 API 實現的複雜性分開,從而隨著 API 的進展或遇到新的錯誤場景,促進添加獨特的異常或變更。

包裝自訂異常

包裝異常涉及捕獲異常,將其封裝在定制的異常中,並引發這個新異常以及原始異常的標識作為其根本原因。這種方法用於為錯誤訊息提供上下文,並隱藏呼叫程式碼的實作細節。

如果 Web 應用程式與 API 通訊並遇到“LookupError”,則可以透過異常處理的方式擷取此錯誤。隨後,可以產生一個自訂的「APINotFoundError」異常,該異常作為 Python 中原始「Exception」類別的衍生類別。這個新的異常可能包括初始的「LookupError」作為其潛在的致病因素,從而提供有關當前特定問題的附加上下文。

 def request_api():
    try:
        # Simulate an API error for demonstration purposes
        # Assuming the external API raised a LookupError
        raise LookupError("Sorry, You Encountered A LookUpError !!!")
    except LookupError as original_exception:
        try:
            # Wrap the original exception with a custom exception
            raise APINotFoundError \
                 ("Requested resource not found.") from original_exception
        except APINotFoundError as wrapped_exception:
            # Handle the wrapped exception here
             print(f"Caught wrapped API exception: {wrapped_exception}")

            # or re-raise it if necessary
            raise

try:
    request_api()
except APINotFoundError as err:
    print(f"Caught API exception: {err.__cause__}")

將「from」子句與「raise」語句結合使用來暗示您自訂的異常中的初始異常。

/bc/images/wrapping-custom-exception.jpg

自訂異常將原始異常作為其根本原因,賦予其因果關係,可以追溯到問題的根源。透過檢查該屬性,人們可以辨別運行時執行期間遇到的任何差異或異常的根源。

封裝異常允許提供更實質的上下文,同時向最終用戶傳輸更相關的錯誤通知,而無需公開程式碼或 API 的複雜工作原理。此外,它還有助於以有序且一致的方式組織和解決不同類型的錯誤。

在 Python 中自訂類別行為

透過繼承Python提供的異常基類,我們可以開發基本但有效的異常,以便在程式碼中發生特定錯誤時引發。此外,透過實作神奇或「dunder」方法,可以為異常類別建立自訂行為。