单独处理特定异常(例如,ENOENT)

时间:2017-07-28 18:46:45

标签: python exception exception-handling

在Python中,特定的POSIX错误条件没有单独的异常类型 - 它们由OSError异常对象内的属性区分。

让我们假设我正在执行文件操作(通过SFTP删除可能不存在的文件)并且我想忽略ENOENT,但仍然处理任何其他错误或异常。是否有可能比以下更优雅地做到这一点?

try:
    action()
except OSError as e:
    if e.errno == errno.ENOENT:
        pass
    else:
        sophisticated_error_handling(e)
except e:
    sophisticated_error_handling(e)

我不喜欢这种方法,因为它涉及重复。

注意:没有X-Y问题。 “action”是一个库函数,不能告诉它忽略ENOENT。

2 个答案:

答案 0 :(得分:2)

实现相同结果的方法比您提出的代码更短,更惯用。

您可以尝试/捕获预期的错误,然后检查except子句中错误对象的条件。技巧是,如果错误对象不是您期望的特定子类型,则重新引发相同的错误对象。

import errno
try:
    action()
except IOError as ioe:
    if ioe.errno not in (errno.ENOENT,):
        # this re-raises the same error object.
        raise
    pass # ENOENT. that line is optional, but it makes it look
         # explicit and intentional to fall through the exception handler.

仅使用raise(不带参数)重新引发初始错误很重要。您可能会被raise ioe吸引而不是那条线上的raise吸引。即使您保留相同的错误消息,但如果使用raise ioe,它也会使错误的堆栈跟踪看起来就像错误发生在该行中一样,而不是在错误发生的action()内部。

在您建议的代码中,即使您的第二个异常处理程序在语法上有效,也不会触发它。您必须指定except eexcept <type>:

如果您要进行其他复杂的错误处理,以确保正确性,则可以将所有以前的try / catch嵌套在外部except <type> as <variable>: / try中:

except

当嵌套这样的异常处理程序时,您要注意的一件事是,异常处理程序也可以引发异常。 here文档中有一个有关异常处理的教程,但是您可能会发现它有点密集。

方法2

如果您喜欢meta-python技巧,则可以考虑使用with statement的方法。您可以创建一个能够吸收特定类型错误的python上下文管理器。

try:
    try:
        action()
    except IOError as ioe:
        if ioe.errno not in (errno.ENOENT,): raise
except IOError as any_other_ioerror:
    # this is reached in case you get other errno values
    sophisticated_error_handling()
except OtherExceptionTypeICareAbout as other:
    other_fancy_handler()

然后您可以编写简单的代码,例如:

# add this to your utilities
class absorb(object):
    def __init__(self, *codes):
        self.codes = codes
    def __exit__(self, exc_type, value, traceback):
        if hasattr(value, "errno") and getattr(value, "errno") in self.codes:
            return True # exception is suppressed
        return False # exception is re-raised
    def __enter__(self):
        return None

如果您仍然希望针对其他errno情况进行复杂的错误处理,则可以将上述内容包含在try / except中,如下所示:

# if ENOENT occurs during the block, abort the block, but do not raise.
with absorb(errno.ENOENT):
    delete_my_file_whether_it_exists_or_not()
    print("file deleted.") # reachable only if previous call returned

注意:您可能还想看看contextlib,它可能会为您消除一些元缺陷。

答案 1 :(得分:-1)

接下来只需输入错误类型即可!

test = [1, 2, 3, 4, 5, 6, 'aasd']
for  i in range(50):
   try:
      print(test[i])
except IndexError:
   pass