繁体   English   中英

嵌套 try-except 块会导致代码过度缩进

[英]Nesting try-except blocks leads to overly indented code

我在编写 Python 代码时遇到了一个相当哲学的问题。 通常,使用尽可能多的try-except-else块来处理所有可预期的情况被认为是一种很好的风格。 但我发现这种方法有时会导致不必要的多级缩进,这使得很难将行数保持在 80 以下,并暗示代码中不存在层次结构。 我觉得我缺少某种“GOTO”语句或类似的跳转来应对这个问题。 因此,我想知道我是否缺少一些编码风格、Python 语句或模式来改进我的 Python 代码。

我举一个更具体的例子。 让我们认为我正在定义一个函数,并且我在一个循环中,在那里各种事情可能会出错。 每件事都足以使循环中的其余代码可跳过,我通常以类似于以下方式continue跳过这些代码:

def mu_func()
    failed = False
    for i in range(100):
        try:
            pass
            # we try something that might raise an exception
        except:
            print("something went wrong by reason #1")
            failed = True
            continue
        try:
            pass
            # we try something that might raise an exception
        except:
            print("something went wrong by reason #2")
            failed = True
            continue
        try:
            pass
            # we try something that might raise an exception
        except:
            print("something went wrong by reason #3")
            failed = True
    # some cleanup code at the end of the function
    # that depends on the errors raised
    return failed

这里要注意的重要一点是,由于我们处于循环中,如果引发任何异常, continue语句使我不必使用else语句跳过其余代码。 因此,缩进级别不会继续增长。 另请注意,我不能只是退出异常处理,因为我需要在从函数返回之前进行一些清理。

现在注意当我们不在循环中时会发生什么:

def mu_func()
    failed = False
    try:
        pass
        # we try something that might raise an exception
    except:
        print("something went wrong by reason #1")
        failed = True
    else:
        try:
            pass
            # we try something that might raise an exception
        except:
            print("something went wrong by reason #2")
            failed = True
        else:
            try:
                pass
                # we try something that might raise an exception
            except:
                print("something went wrong by reason #3")
               failed = True
    # some cleanup code at the end of the function
    # that depends on the errors raised
    return failed

看到不同? 如果想在引发任何异常后跳过其余代码,我必须将下面的所有内容放入else语句中,从那时起,它会略微增加缩进级别。 这不仅会导致难以将行数保持在 80 个字符以下的烦人代码。 最糟糕的是,这些嵌套的try-except-else块暗示了代码中的某种层次结构,这是人为的。 所有例外都同等重要。 在第一个示例中可以很容易地理解这一点,其中可以很好地交换try-except块的顺序,而无需触及缩进且不影响功能。

是否有 Python 语句或模式允许我在处理异常后跳过其余代码,从而使我不必添加越来越多的缩进级别? 我是否误用了else语句? 我很想把所有东西都放在一个简单的 1 次迭代循环中,这样我就可以访问continue语句来执行跳转到我遗漏的块语句的末尾

一种方法可能是用try-except块包装 for 循环:

def mu_func():
    try:
        for i in range(100):
            # we try something that might raise an exception
            action_1()
            print("action #1 succeeds")

            action_2()
            print("action #2 succeeds")

            action_3()
            print("action #3 succeeds")

    except:
        print("something went wrong!")
        failed = True

    else:
        failed = False

    return failed

如果你的 for 循环中有其他逻辑,我建议只包装可能引发异常的逻辑:

def mu_func():
    for i in range(100):
        try:
            # we try something that might raise an exception
            action_1()
            print("action #1 succeeds")

            action_2()
            print("action #2 succeeds")

            action_3()
            print("action #3 succeeds")

        except:
            print("something went wrong!")
            failed = True
            break

        # here we might do other stuff in the loop
        ...
    
    else:
        failed = False

    return failed

怎么用:

def mu_func()
    failed = False
    try:
        pass
        # we try something that might raise an exception
    except ExceptionClass1():
        print("something went wrong by reason #1")
        failed = True
    except ExceptionClass2():
        print("something went wrong by reason #2")
        failed = True
    except ExceptionClass3():
        print("something went wrong by reason #3")
        failed = True
    except ExceptionClass4():
        print("something went wrong by reason #4")
        failed = True
    return failed

我找到了 2 个解决问题的方法。 我会将它们张贴在这里以激发进一步的讨论或在我的情况下帮助其他人。 不过,我不会将此标记为答案,因为我发现它们更像是一种解决方法而不是正确的解决方案。 它们在某种程度上是基于这个问题的答案(我认为它接受的答案不能解决问题)。

使用虚拟循环的解决方案

这里的想法是伪造一个循环来访问允许您跳转到函数末尾的continue语句。

def mu_func()
    failed = False
    for _ in range(1):
        try:
            pass
            # we try something that might raise an exception
        except Exception1:
            print("something went wrong by reason #1")
            failed = True
            continue
        try:
            pass
            # we try something that might raise an exception
        except Exception2:
            print("something went wrong by reason #2")
            failed = True
            continue
        try:
            pass
            # we try something that might raise an exception
        except Exception3:
            print("something went wrong by reason #3")
            failed = True
    # some cleanup code at the end of the function
    # that must be executed before leaving
    return failed

这个解决方案有效,但它非常丑陋,因为以一种创造性的方式使用 for 循环,这显然不是它的设计目的。

使用2级异常处理的解决方案

这里的想法是定义和使用通用异常,并使用它来转换异常类型以表示出现问题(但它已经被处理),然后基本上将执行流程发送到最后。

class MyException(Exception):
    pass

def mu_func()
    failed = False
    try:
        try:
            pass
            # we try something that might raise an exception
        except Exception1:
            print("something went wrong by reason #1")
            raise MyException
        try:
            pass
            # we try something that might raise an exception
        except Exception2:
            print("something went wrong by reason #2")
            raise MyException
        try:
            pass
            # we try something that might raise an exception
        except Exception3:
            print("something went wrong by reason #3")
            raise MyException
    except MyException:
        failed = True
    # some cleanup code at the end of the function
    # that depends on the errors raised
    return failed

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM