在現代Python中聲明自定義異常的正確方法?

在現代Python中聲明自定義異常類的正確方法是什麼? 個人主要目標是遵循其餘異常類具備的任何標準,以便(例如)我捕獲到異常中的任何工具都會打印出我包含在異常中的任何多餘字符串。 html

「現代Python」是指能夠在Python 2.5中運行但對於Python 2.6和Python 3. *是「正確」的方式。 所謂「自定義」,是指一個Exception對象,該對象能夠包含有關錯誤緣由的其餘數據:字符串,也許還包括與該異常相關的其餘任意對象。 python

我在Python 2.6.2中被如下棄用警告絆倒了: app

>>> 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收集到,該屬性確實在2.5中有特殊含義,所以他們想棄用該屬性,因此我猜測如今禁止使用該名稱(以及一我的)。 啊。 工具

我也模糊地知道Exception有一些魔術參數args ,可是我歷來不知道如何使用它。 我也不肯定這是前進的正確方法。 我在網上發現的不少討論都代表他們正在嘗試消除Python 3中的args。 spa

更新:有兩個答案建議覆蓋__init____str__ / __unicode__ / __repr__ 。 好像要打不少筆,有必要嗎? code


#1樓

使用現代的Python異常,您不須要濫用.message ,也沒必要覆蓋.__str__().__repr__()或任何它。 若是在引起異常時,您所但願的只是一條提示性消​​息,請執行如下操做: htm

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子類化。

class MyError(Exception):
    def __init__(self, message, animal):
        self.message = message
        self.animal = animal
    def __str__(self):
        return self.message

#2樓

您應該重寫__repr____unicode__方法而不是使用message,構造異常時提供的args將位於異常對象的args屬性中。


#3樓

也許我錯過了這個問題,可是爲何不呢?

class MyException(Exception):
    pass

編輯:要覆蓋某些內容(或傳遞額外的args),請執行如下操做:

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到達它。


Python 3更新:在Python 3+中,您可使用對super()這種更爲緊湊的用法:

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

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

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

#4樓

不,「消息」不是禁止的。 只是過期了。 您的應用程序能夠正常使用消息。 可是,您固然能夠擺脫折舊錯誤。

當爲應用程序建立自定義Exception類時,它們中的許多不只僅從Exception繼承子類,還從ValueError之類的其餘子類繼承。 而後,您必須適應它們對變量的使用。

並且,若是您的應用程序中有不少異常,一般最好爲全部異常都擁有一個通用的自定義基類,以便模塊的用戶能夠

try:
    ...
except NelsonsExceptions:
    ...

在那種狀況下,您能夠在那裏__init__ and __str__所需的__init__ and __str__ ,所以您沒必要爲每一個異常重複此操做。 可是簡單地調用message變量而不是message能夠解決問題。

不管如何,若是您作的事情與Exception自己不一樣,則只須要__init__ or __str__ 。 而且由於若是不同意使用,那麼您將同時須要這兩種方法,不然會出錯。 每一個類不須要不少額外的代碼。 ;)


#5樓

見異常缺省狀況下是如何工做的,若是一個VS多個屬性使用(回溯略):

>>> raise Exception('bad thing happened')
Exception: bad thing happened

>>> raise Exception('bad thing happened', 'code is broken')
Exception: ('bad thing happened', 'code is broken')

所以,您可能須要一種「 異常模板 」,以兼容的方式做爲異常自己工做:

>>> nastyerr = NastyError('bad thing happened')
>>> raise nastyerr
NastyError: bad thing happened

>>> raise nastyerr()
NastyError: bad thing happened

>>> raise nastyerr('code is broken')
NastyError: ('bad thing happened', 'code is broken')

使用此子類能夠輕鬆完成此操做

class ExceptionTemplate(Exception):
    def __call__(self, *args):
        return self.__class__(*(self.args + args))
# ...
class NastyError(ExceptionTemplate): pass

若是您不喜歡默認的相似元組的表示形式,只需將__str__方法添加到ExceptionTemplate類中,例如:

# ...
    def __str__(self):
        return ': '.join(self.args)

而後你會

>>> raise nastyerr('code is broken')
NastyError: bad thing happened: code is broken
相關文章
相關標籤/搜索