【问题标题】:try-except block: analogue for 'else' if exception was raisedtry-except 块:如果引发异常,则与“else”类似
【发布时间】:2016-02-12 07:48:22
【问题描述】:

我有这样的代码:

try:
    return make_success_result()
except FirstException:
    handle_first_exception()
    return make_error_result()
except SecondException:
    handle_second_exception()
    return make_error_result()

我想知道有什么办法可以做到这一点:

try:
    # do something
except Error1:
    # do Error1 specific handling
except Error2:
    # do Error2 specific handling
else:
    # do this if there was no exception
????:
    # ALSO do this if there was ANY of the listed exceptions (e.g. some common error handling)

所以代码按以下顺序之一执行:

try > else > finally
try > except > ???? > finally

编辑:我的意思是???? 块应该在任何except 块之后立即执行,这意味着它是对错误处理的补充,而不是替代。

【问题讨论】:

    标签: python exception exception-handling try-except


    【解决方案1】:

    您实际上可以这样做:

    try:
        print 'try'
        # 1/0
        # {}[1]
        # {}.a
    except AttributeError, KeyError:  # only handle these exceptions..
        try:
            raise                     # re-raise the exception so we can add a finally-clause executing iff there was an exception.
        except AttributeError:
            print 'attrerr'
            # raise ...               # any raises here will also execute 'common'
        except KeyError:
            print 'keyerror'
        finally:                      # update 0: you wanted the common code after the exceptions..
            print "common"
    
    else:
        print 'no exception'
    

    但这很可怕,我不建议你在没有大量 cmet 描述原因的情况下这样做..

    更新:除了内部 try 块中有趣的异常之外,您不需要捕获任何内容。代码已更新。

    UPDATE2: 根据 OP 的说明,common 应该只在引发有趣的异常时执行。代码已更新。 @MattTaylor 的版本绝对是要走的路;-)

    【讨论】:

    • 哪个 IMO 使我的回答成为问题的最干净的解决方案。你是对的,它读起来不太好。我已经更新了我的答案,包括使用 else: 语句。
    • thebjorn,是的,这太复杂了,到目前为止,马特·泰勒的回答确实是最干净的
    【解决方案2】:

    您可以捕获所有错误并在错误处理代码中检查其类型,如下所示:

    try:
        # do something
    except Exception as e:
        if isinstance(e, Error1):
            # do Error1 specific handling
        elif isinstance(e, Error2):
            # do Error2 specific handling
        else:
            # do non-Error1/Error2 handling
        # ALSO do this if there was ANY exception (e.g. some common error handling)
    else:
        # do this if there was no exception
    

    【讨论】:

    • @thebjorn 总是如此,即使您使用 finally 子句。如果您在错误处理代码中遇到错误,一切都会丢失。
    【解决方案3】:

    在这种情况下,我会在遇到异常时设置一个布尔值,如下所示:

    got_exception = False
    try:
        # do something
    except Error1:
        # do Error1 specific handling
        got_exception = True
    except Error2:
        # do Error2 specific handling
        got_exception = True
    else:
        # If there was no exception
    finally:
        if got_exception:
            # ALSO do this if there was ANY exception (e.g. some common error handling)
    

    这应该符合您的需求,这是 IMO 将所有已呈现的解决方案组合成最易调试的最易读代码结构的最简洁方式。

    【讨论】:

    • python中已经有一个内置的解决方案可以做到这一点,看我的评论
    • 如果你没有捕捉到except Exception:(或者只是except:),那么任何没有被明确捕捉到的异常都会在finally:子句之后转义,并且got_exception变量不会被设置...
    • @thebjorn 据我所知,这不是真的,如果发生未明确捕获的异常,那么它将运行try/finally 块,然后抛出错误。只有当你做的事情吞噬了finally 中的everything 时,通用的Exception 才会通过
    • @MattTaylor 问题是如果Error1 或Error2 以外的其他内容被提出,是否应该执行if got_exception:。就像您现在的代码一样,它不会。 OP 说它应该在引发任何异常时执行(尽管我猜它是开放的,如果这意味着只是列出的任何一个..)
    • @thebjorn 我同意,在我的解释中,这是为了清理预期的异常 - 而不仅仅是捕获任何可能发生的异常。
    【解决方案4】:

    是的,python 中的异常处理包括else 和finally 子句。你可以这样做:

    try:
        # do something
    except Error1:
        # do Error1 specific handling
    except Error2:
        # do Error2 specific handling
    else:
        # do this if there was no exception
    finally:
        # Do this in any case!
    

    python docs 提到了这些块,即使它没有显示您需要的完整示例。


    编辑: 我看到您在一般情况下并没有专门要求进行清理。 Python 文档是这样说的:

    try 语句还有另一个可选子句,旨在定义在所有情况下都必须执行的清理操作。

    请注意,finally 将运行,无论是否有异常。结合else 块,你应该仍然可以做你想做的事。

    【讨论】:

    • finally 不管有没有异常都会执行。 @MedhatGayed 的解决方案是正确的。
    • @thebjorn:你是对的。我在你写评论的那一刻编辑了答案。我仍然认为你可以使用它,只要你确保一切都在正确的块中
    • @mart0903 如果你这样认为,那么你应该编辑你的答案以显示哪些部分需要进入哪个块......(我认为在 finally 子句被调用后未捕获的异常将逃逸不管你如何构建它..)
    • 我知道finally,但它不适合我,因为它会在任何情况下执行。基本上到目前为止唯一有效的解决方案是添加 flag + using finally 正如@MattTaylor 建议的那样,但我想知道是否有一种更清洁的方法而不使用标志
    猜你喜欢
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 2012-05-02
    • 2010-10-22
    • 1970-01-01
    • 2013-08-13
    • 1970-01-01
    • 2020-06-05
    相关资源
    最近更新 更多