“在现代Python中声明自定义异常的正确方法是什么?”
这很好,除非您的异常确实是一种更具体的异常:
class MyException(Exception):
pass
或者更好(也许完美),而不是传递一个docstring:
class MyException(Exception):
"""Raise for my specific kind of exception"""
子类化异常子类
从文档中
例外所有内置的、非系统退出的异常都是从该类派生的。所有用户定义的异常也应由此派生班
这意味着,如果您的异常是一种更具体的异常类型,请将该异常子类化,而不是泛型异常(结果将是您仍然按照文档的建议从异常派生)。此外,您至少可以提供一个docstring(不必强制使用pass关键字):
class MyAppValueError(ValueError):
'''Raise when my specific value is wrong'''
使用自定义__init__设置您自己创建的属性。避免将dict作为位置参数传递,代码的未来用户将感谢您。如果使用不推荐的消息属性,则自行分配该属性将避免出现不推荐的警告:
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进行初始化的方法,如果访问message属性,您将收到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
这样,您就可以将错误消息的dict传递给第二个参数,然后使用e.errors进行处理
它还需要正好传入两个参数(除了self)。这是一个有趣的限制,未来的用户可能不会理解。
直接地说,这违反了利斯科夫的可替代性。
我将演示这两个错误:
>>> 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'