在现代Python中声明自定义异常的正确方法?

2022-09-05 00:52:27

在现代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

对于名为 的属性具有特殊含义,这似乎很疯狂。我从PEP-352中收集到,属性在2.5中确实有特殊的含义,他们正试图弃用,所以我想这个名字(而且只是那个名字)现在被禁止了吗?呸。BaseExceptionmessage

我也模糊地意识到它有一些神奇的参数,但我从来不知道如何使用它。我也不确定这是未来做事的正确方式。我在网上找到的很多讨论都表明他们试图在Python 3中取消args。Exceptionargs

更新:两个答案建议覆盖 和 //。这似乎是很多打字,有必要吗?__init____str____unicode____repr__


答案 1

也许我错过了这个问题,但为什么不:

class MyException(Exception):
    pass

要覆盖某些内容(或传递额外的参数),请执行以下操作:

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

这样,您就可以将错误消息的字典传递给第二个参数,并在以后使用 .e.errors

在Python 2中,你必须使用这种稍微复杂一些的形式:super()

super(ValidationError, self).__init__(message)

答案 2

使用现代Python例外,您不需要滥用 ,或覆盖或或其中任何一个。如果在引发异常时只需要一条信息性消息,请执行以下操作:.message.__str__().__repr__()

class MyException(Exception):
    pass

raise 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"})

但是,在块中获取这些细节要复杂一些。详细信息存储在属性中,该属性是一个列表。您需要执行如下操作:exceptargs

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