14.6 处�多个异常¶

问题¶

你有一个代�片段�能会抛出多个��的异常,怎样�能�创建大���代�就能处�所有的�能异常呢?

解决方案¶

如果你�以用�个代��处���的异常,�以将它们放入一个元组中,如下所示:

try:
    client_obj.get_url(url)
except (URLError, ValueError, SocketTimeout):
    client_obj.remove_url(url)

在这个例�中,元祖中任何一个异常�生时都会执行 remove_url() 方法。 如果你想对其中�个异常进行��的处�,�以将其放入�外一个 except 语�中:

try:
    client_obj.get_url(url)
except (URLError, ValueError):
    client_obj.remove_url(url)
except SocketTimeout:
    client_obj.handle_url_timeout(url)

很多的异常会有层级关系,对于这�情况,你�能使用它们的一个基类��获所有的异常。例如,下�的代�:

try:
    f = open(filename)
except (FileNotFoundError, PermissionError):
    pass

�以被�写为:

try:
    f = open(filename)
except OSError:
    pass

OSError 是 FileNotFoundError 和 PermissionError 异常的基类。

讨论¶

尽管处�多个异常本身并没什么特殊的,�过你�以使用 as 关键字�获得被抛出异常的引用:

try:
    f = open(filename)
except OSError as e:
    if e.errno == errno.ENOENT:
        logger.error('File not found')
    elif e.errno == errno.EACCES:
        logger.error('Permission denied')
    else:
        logger.error('Unexpected error: %d', e.errno)

这个例�中, e ��指�一个被抛出的 OSError 异常实例。 这个在你想更进一步分�这个异常的时候会很有用,比如基于�个状���处�它。

�时还�注�的时候 except 语�是顺�检查的,第一个匹�的会执行。 你�以很容易的构造多个 except �时匹�的情形,比如:

>>> f = open('missing')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: 'missing'
>>> try:
...     f = open('missing')
... except OSError:
...     print('It failed')
... except FileNotFoundError:
...     print('File not found')
...
It failed
>>>

这里的 FileNotFoundError 语�并没有执行的原因是 OSError 更一般,它�匹� FileNotFoundError 异常, 于是就是第一个匹�的。 在调试的时候,如果你对�个特定异常的类�层级关系�是很确定, 你�以通过查看该异常的 __mro__ 属性�快速�览。比如:

>>> FileNotFoundError.__mro__
(<class 'FileNotFoundError'>, <class 'OSError'>, <class 'Exception'>,
 <class 'BaseException'>, <class 'object'>)
>>>

上�列表中任何一个直到 BaseException 的类都能被用于 except 语�。