在现代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
相关文章
相关标签/搜索