14.8 创建自定义异常¶

问题¶

在你构建的应用程�中,你想将底层异常包装�自定义的异常。

解决方案¶

创建新的异常很简�——定义新的类,让它继承自 Exception (或者是任何一个已存在的异常类型)。 例如,如果你编写网络相关的程�,你�能会定义一些类似如下的异常:

class NetworkError(Exception):
    pass

class HostnameError(NetworkError):
    pass

class TimeoutError(NetworkError):
    pass

class ProtocolError(NetworkError):
    pass

然�用户就�以�通常那样使用这些异常了,例如:

try:
    msg = s.recv()
except TimeoutError as e:
    ...
except ProtocolError as e:
    ...

讨论¶

自定义异常类应该总是继承自内置的 Exception 类, 或者是继承自那些本身就是从 Exception 继承而�的类。 尽管所有类�时也继承自 BaseException ,但你�应该使用这个基类�定义新的异常。 BaseException 是为系统退出异常而�留的,比如 KeyboardInterrupt 或 SystemExit 以�其他那些会给应用��信�而退出的异常。 因此,�获这些异常本身没什么�义。 这样的�,�如你继承 BaseException �能会导致你的自定义异常�会被�获而直接��信�退出程��行。

在程�中引入自定义异常�以使得你的代�更具�读性,能清晰显示�应该阅读这个代�。 还有一�设计是将自定义异常通过继承组�起�。在��应用程�中, 使用基类�分组��异常类也是很有用的。它�以让用户�获一个范围很窄的特定异常,比如下�这样的:

try:
    s.send(msg)
except ProtocolError:
    ...

你还能�获更大范围的异常,就�下�这样:

try:
    s.send(msg)
except NetworkError:
    ...

如果你想定义的新异常�写了 __init__() 方法, 确�你使用所有�数调用 Exception.__init__() ,例如:

class CustomError(Exception):
    def __init__(self, message, status):
        super().__init__(message, status)
        self.message = message
        self.status = status

看上去有点奇怪,�过Exception的默认行为是接�所有传递的�数并将它们以元组形�存储在 .args 属性中. 很多其他函数库和部分Python库默认所有异常都必须有 .args 属性, 因此如果你忽略了这一步,你会�现有些时候你定义的新异常�会按照期望�行。 为了演示 .args 的使用,考虑下下�这个使用内置的 RuntimeError` 异常的交互会�, 注�看raise语�中使用的�数个数是怎样的:

>>> try:
...     raise RuntimeError('It failed')
... except RuntimeError as e:
...     print(e.args)
...
('It failed',)
>>> try:
...     raise RuntimeError('It failed', 42, 'spam')
... except RuntimeError as e:

...     print(e.args)
...
('It failed', 42, 'spam')
>>>

关于创建自定义异常的更多信�,请�考`Python官方文档 <https://docs.python.org/3/tutorial/errors.html>`_