try - python3 exception message




在現代Python中聲明自定義異常的正確方法是什麼? (4)

“在現代Python中聲明自定義異常的正確方法是什麼?”

這很好,除非你的異常真的是一種更具體的異常:

class MyException(Exception):
    pass

或者更好(也許完美),而不是pass給文檔字符串:

class MyException(Exception):
    """Raise for my specific kind of exception"""

子類異常子類

來自docs

Exception

所有內置的,非系統退出的異常都源自這個類。 所有用戶定義的異常也應該從這個類派生。

這意味著如果您的異常是一種更具體的異常,則將該異常的子類替換為通用的Exception (並且結果將是您仍然從文檔推薦的Exception派生出來的Exception )。 此外,你至少可以提供一個文檔字符串(而不是強制使用pass關鍵字):

class MyAppValueError(ValueError):
    '''Raise when my specific value is wrong'''

使用自定義__init__設置您自己創建的屬性。 避免將字典作為位置參數傳遞,未來的代碼用戶會感謝您。 如果您使用棄用的消息屬性,則自行分配它將避免棄用警告:

class MyAppValueError(ValueError):
    '''Raise when a specific subset of values in context of app is wrong'''
    def __init__(self, message, foo, *args):
        self.message = message # without this you may get DeprecationWarning
        # Special attribute you desire with your Error, 
        # perhaps the value that caused the error?:
        self.foo = foo         
        # allow users initialize misc. arguments as any other builtin Error
        super(MyAppValueError, self).__init__(message, foo, *args) 

真的不需要編寫自己的__str____repr__ 。 內置的非常好,你的合作繼承可以確保你使用它。

對最佳答案的評論

也許我錯過了這個問題,但為什麼不:

class MyException(Exception):
    pass

同樣,上面的問題是,為了捕獲它,你要么專門命名它(如果在其他地方創建它,則要導入它)或捕獲異常(但是你可能不准備處理所有類型的異常,你應該只捕捉你準備處理的異常)。 類似的批評,以下,但另外,這不是通過super初始化的方式,如果您訪問消息屬性,您會得到一個DeprecationWarning

編輯:重寫某些內容(或傳遞額外的參數),請執行以下操作:

class ValidationError(Exception):
    def __init__(self, message, errors):

        # Call the base class constructor with the parameters it needs
        super(ValidationError, self).__init__(message)

        # Now for your custom code...
        self.errors = errors

這樣你就可以將錯誤消息的字典傳遞給第二個參數,並在晚些時候使用e.errors進行處理

它還需要準確地傳遞兩個參數(除了self 。不多也不少。 這是一個有趣的限制,未來的用戶可能不會感激。

直接 - 它違反了Liskov可替代性

我將演示這兩個錯誤:

>>> ValidationError('foo', 'bar', 'baz').message

Traceback (most recent call last):
  File "<pyshell#10>", line 1, in <module>
    ValidationError('foo', 'bar', 'baz').message
TypeError: __init__() takes exactly 3 arguments (4 given)

>>> ValidationError('foo', 'bar').message
__main__:1: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6
'foo'

相比:

>>> MyAppValueError('foo', 'FOO', 'bar').message
'foo'

在現代Python中聲明自定義異常類的正確方法是什麼? 我的主要目標是遵循其他任何標準的異常類,以便(例如)任何額外的字符串,我包括在例外中,通過任何工具捕獲異常打印出來。

對於“現代Python”,我的意思是可以在Python 2.5中運行的東西,但對於Python 2.6和Python 3 *做事情的方式是“正確的”。 通過“自定義”,我的意思是一個Exception對象,它可以包含關於錯誤原因的額外數據:一個字符串,也許還有一些其他與異常相關的任意對象。

在Python 2.6.2中,我被下面的棄用警告絆倒了:

>>> class MyError(Exception):
...     def __init__(self, message):
...         self.message = message
... 
>>> MyError("foo")
_sandbox.py:3: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6

BaseException對於名為message屬性有特殊的含義似乎很瘋狂。 我從PEP-352那裡收集到PEP-352那個屬性在2.5中有一個特殊的含義,他們試圖貶低它,所以我猜這個名字(現在只有一個)現在被禁止了? 啊。

我也模糊地意識到, Exception有一些神奇的參數args ,但我從來不知道如何使用它。 我也不確定這是做事的正確方法; 我在網上發現的很多討論都表明他們試圖取消Python 3中的參數。

更新:兩個答案建議覆蓋__init____str__ / __unicode__ / __repr__ 。 這似乎很多打字,是否有必要?


不,“消息”不被禁止。 它只是被棄用。 您的應用程序將使用消息正常工作。 但是,當然,您可能希望擺脫棄用錯誤。

當你為你的應用程序創建自定義的Exception類時,它們中的很多不僅僅是來自Exception的子類,而是其他類,比如ValueError或類似的。 然後你必須適應他們對變量的使用。

如果您的應用程序中有很多例外情況,那麼為所有這些應用程序提供一個通用的自定義基類通常是一個好主意,以便您的模塊的用戶可以執行

try:
    ...
except NelsonsExceptions:
    ...

在這種情況下,您可以在那裡__init__ and __str__所需的__init__ and __str__ ,因此您不必為每個異常都重複一遍。 但是簡單地調用消息變量除了消息之外還有其他的竅門。

在任何情況下,如果您執行與Exception本身不同的操作,則只需要__init__ or __str__ 。 而且,因為如果棄用,那麼您需要這兩者,否則您會得到一個錯誤。 這不是每個班級所需的額外代碼。 ;)


使用現代Python例外,您不需要濫用.message ,或覆蓋.__str__().__repr__()或其中任何一個。 如果所有你想要的是一個提供異常信息的消息,請執行以下操作:

class MyException(Exception):
    pass

raise MyException("My hovercraft is full of eels")

這將以MyException: My hovercraft is full of eels結束回溯MyException: My hovercraft is full of eels

如果你想要更多的靈活性,你可以傳遞一個字典作為參數:

raise MyException({"message":"My hovercraft is full of animals", "animal":"eels"})

但是,要在一個except塊中獲得這些細節則要復雜一點。 它們存儲在args屬性中,該屬性是一個列表。 你需要做這樣的事情:

try:
    raise MyException({"message":"My hovercraft is full of animals", "animal":"eels"})
except MyException as e:
    details = e.args[0]
    print(details["animal"])

仍有可能將多個項目傳遞給異常,但將來將不再使用。 如果您確實需要多個信息,那麼您應該考慮完全繼承Exception


您應該覆蓋__repr____unicode__方法而不是使用消息,您在構造異常時提供的args將位於異常對象的args屬性中。







exception