【问题标题】:Neater way to catch exception in exception handler in Python在 Python 中的异常处理程序中捕获异常的更简洁的方法
【发布时间】:2017-11-10 05:05:27
【问题描述】:

在 Python 程序中,通常使用 try-except 块捕获异常:

try:
    # Do stuff
except ValueError:
    # Handle exception

我知道在异常处理程序中捕获异常的最佳方法是嵌套的 try-except 块。但是,对于许多嵌套的 try-catch 块,这可能会有点混乱:

try:
    # Some assignment that throws an exception if the object is not in the list
    try:
        # Some assignment function that throws an exception if the the object is not already in the database
        # Error Handling
    except ValueError:
        try:
            # Some function that throws an exception if the object does not have an undesired property
            # Error Handling
        except AttributeError:
            try:
                # Some function that throws an exception if an error happens
            except Exception:
                # Exception handling
except ValueError:
    # Exception handling

有没有更简洁的方法来做到这一点?比如:

try:
   # Some assignment that throws an exception if the object is not in the list
   try:
       # Some assignment function that throws an exception if the object is not already in the database
   except ValueError:
       # Some function that throws an exception if the object does not have an undesired property
   exceptexcept AttributeError:
       # Some function that throws an exception if an error happens
   exceptexcept Exception:
       # Exception handling 
except ValueError:
   # Exception handling

【问题讨论】:

  • 在您的最后一个区块中,您对exceptexcept 的意图是什么?如果这些只是except,那么您的代码可能会像您期望的那样工作。 (需要注意的是,外部 ValueError 只会捕获发生在 外部 内部 try 块的异常(因为这些异常至少会被最后一个 except Exception 块捕获)。
  • 我试图在 except 子句中捕获异常,而不是在 try 中。
  • 假设您试图在错误处理代码中捕捉错误,那么就没有什么可做的了。您必须使用这种嵌套层次结构。
  • 抱歉造成误会,在你描述的情况下我同意coldspeed。
  • 就像他们说的,你被嵌套困住了。所以这个故事的寓意是:尽量避免在except 块中使用可能引发异常的代码。 ;)

标签: python exception exception-handling


【解决方案1】:

这听起来像是一个循环,您想继续尝试直到成功或用尽选项。所以你可以这样实现它,例如,像这样

# Each pair contains a function to call and an exception that can be caught.
# If that exception is raised, the next function will be tried.
action_list = [
    (get_from_list, ValueError),  # throws ValueError if item can't be retrieved
    (get_from_database, ValueError),  # throws ValueError if item can't be retrieved
    (get_from_object, AttributeError),  # throws AttributeError if item lacks desired property
]

result = None
for action, ex in action_list:
    try:
        result = action(key)
        break
    except ex:
        continue

您可以通过让所有辅助函数引发自定义异常(如“NotFound”)来稍微整理一下,然后将其用作检查下一个级别的信号,如下所示:

# actions to try; all raise NotFound if unsuccessful
action_list = [
    get_from_list, get_from_database, get_from_object
]

result = None
for action in action_list:
    try:
        result = action(key)
        break
    except NotFound:
        continue

或者您可以将所有步骤放在一个函数中,该函数一旦成功就返回。这样你的任务可以在常规代码中完成,而不是使用辅助函数:

def get_value(key):

    try:
        return some_list[int(key)]
    except ValueError:
        pass

    try:
        return get_from_database(key)
    except ValueError:
        pass

    try:
        return getattr(some_object, key)
    except AttributeError:
        pass

    return None

如果您不想要其他功能,您可以滥用for 循环:

result = None
for _ in range(1):

    try:
        result = some_list[int(key)]
        break
    except ValueError:
        pass

    try:
        result = get_from_database(key)
        break
    except ValueError:
        pass

    try:
        result = getattr(some_object, key)
        break
    except AttributeError:
        pass

或者您可以使用单个外部 try/except 和自定义 Found 异常作为“structured goto”:

result = None
try:
    try:
        result = some_list[int(key)]
        raise Found
    except ValueError:
        pass
    try:
        result = get_from_database(key)
        raise Found
    except ValueError:
        pass
    try:
        result = getattr(some_object, key)
        raise Found
    except AttributeError:
        pass
except Found:
    pass  # all good

或者有这个久经考验的构造:

result = None
if result is None:
    try:
        result = some_list[int(key)]
    except ValueError:
        pass
if result is None:
    try:
        result = get_from_database(key)
    except ValueError:
        pass
if result is None:
    try:
        result = getattr(some_object, key)
    except AttributeError:
        pass

【讨论】:

    【解决方案2】:

    是的。您可以在 python 中使用异常层次结构。 应注意例外的顺序。捕获错误的 except 将被执行,其余的都将被忽略。

    做,

    inspect.getclasstree(inspect.getmro(Exception))
    
     BaseException
    ... Exception
    ...... StandardError
    ......... TypeError
    ......... ImportError
    ............ ZipImportError
    ......... EnvironmentError
    ............ IOError
    ............... ItimerError
    ............ OSError
    ......... EOFError
    ......... RuntimeError
    ............ NotImplementedError
    ......... NameError
    ............ UnboundLocalError
    ......... AttributeError
    ......... SyntaxError
    ............ IndentationError
    ............... TabError
    ......... LookupError
    ............ IndexError
    ............ KeyError
    ............ CodecRegistryError
    ......... ValueError
    ............ UnicodeError
    ............... UnicodeEncodeError
    ............... UnicodeDecodeError
    ............... UnicodeTranslateError
    ......... AssertionError
    ......... ArithmeticError
    ............ FloatingPointError
    ............ OverflowError
    ............ ZeroDivisionError
    ......... SystemError
    ............ CodecRegistryError
    ......... ReferenceError
    ......... MemoryError
    ......... BufferError
    

    【讨论】:

    • OP应该如何使用它?发布异常树并不会使其非常明显。
    • 我不是试图在第一个函数中捕获不同的异常,而是在每个连续的块中,我试图在前一个块(处理程序)中捕获异常。我没有看到比嵌套 try-except 块更好的方法,但是那样会变得非常混乱。我在寻求更好的方法。
    • 你是不是抄袭了stackoverflow.com/a/18296681/4909087的这个答案?
    • 一个明显的答案没有什么可以抄袭的,我从 2014 年保存的记事本中复制了这棵树。
    猜你喜欢
    • 2014-09-03
    • 1970-01-01
    • 1970-01-01
    • 2017-10-25
    • 2017-05-02
    • 2023-02-06
    • 2015-10-02
    • 1970-01-01
    • 2015-01-02
    相关资源
    最近更新 更多