[英]Nesting try-except blocks leads to overly indented code
I have a rather philosophical problem writing Python code.我在编写 Python 代码时遇到了一个相当哲学的问题。 Normally it is considered good style to use as many
try-except-else
blocks as necessary to handle all expectable cases.通常,使用尽可能多的
try-except-else
块来处理所有可预期的情况被认为是一种很好的风格。 But I find that this is approach sometimes leads to unnecessarily many levels of indentation that makes it difficult to keep the line count below 80 and suggest nonexistent hierarchical structure in the code.但我发现这种方法有时会导致不必要的多级缩进,这使得很难将行数保持在 80 以下,并暗示代码中不存在层次结构。 I feel I'm missing some sort of "GOTO" statement or similar jump to cope with this.
我觉得我缺少某种“GOTO”语句或类似的跳转来应对这个问题。 Therefore I'm wondering if I'm missing some coding style, or Python statement, or pattern, to improve my Python code.
因此,我想知道我是否缺少一些编码风格、Python 语句或模式来改进我的 Python 代码。
I'll put a more concrete example.我举一个更具体的例子。 Let's think I'm defining a function, and I'm within a loop, where various things could go wrong.
让我们认为我正在定义一个函数,并且我在一个循环中,在那里各种事情可能会出错。 Each thing is sufficient to make the rest of the code within the loop skippable, which I normally skip with
continue
in a way similar to:每件事都足以使循环中的其余代码可跳过,我通常以类似于以下方式
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
The important thing to note here is that since we are within a loop, the continue
statement saves me from having to use an else
statement to skip the rest of the code if any exception is raised.这里要注意的重要一点是,由于我们处于循环中,如果引发任何异常,
continue
语句使我不必使用else
语句跳过其余代码。 Therefore the indentation level does not keep growing.因此,缩进级别不会继续增长。 Also note that I cannot just exit from the exception handling, because I need to do some cleanup right before returning from the function.
另请注意,我不能只是退出异常处理,因为我需要在从函数返回之前进行一些清理。
Now note what happens when we are not within a loop :现在注意当我们不在循环中时会发生什么:
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
¿See the difference?看到不同? If want to skip the rest of the code after any exception has been raised, I have to put inside an
else
statement everything below, which trivially increases a level of indent from that point on.如果想在引发任何异常后跳过其余代码,我必须将下面的所有内容放入
else
语句中,从那时起,它会略微增加缩进级别。 This not only leads to annoying code where it is difficult to to keep the line count below 80 characters.这不仅会导致难以将行数保持在 80 个字符以下的烦人代码。 The worst aspect is that these nested
try-except-else
blocks suggest some sort of hierarchy in the code, which is artificial.最糟糕的是,这些嵌套的
try-except-else
块暗示了代码中的某种层次结构,这是人为的。 All exceptions are equally important.所有例外都同等重要。 This can be easily appreciated in the first example where the order of the
try-except
blocks could be nicely exchanged without touching the indent and without affecting the functionality.在第一个示例中可以很容易地理解这一点,其中可以很好地交换
try-except
块的顺序,而无需触及缩进且不影响功能。
Is there a Python statement, or pattern, that allows me to skip the rest of the code once an exception is handled, that precludes me from having to add more and more indent levels?是否有 Python 语句或模式允许我在处理异常后跳过其余代码,从而使我不必添加越来越多的缩进级别? Am I misusing the
else
statement?我是否误用了
else
语句? I'm tempted to put everything within a trivial 1-iteration loop so I have access to the continue
statement to perform the jump to the end of block statement that I'm missing.我很想把所有东西都放在一个简单的 1 次迭代循环中,这样我就可以访问
continue
语句来执行跳转到我遗漏的块语句的末尾。
One approach might be to wrap the for loop with a try-except
block:一种方法可能是用
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
If you have other logic in your for loop, I'd suggest wrapping only the logic that might raise an exception:如果你的 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
What about using:怎么用:
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
I have found 2 solutions to the problem.我找到了 2 个解决问题的方法。 I'll post them here to either stimulate further discussion or help others in my situation.
我会将它们张贴在这里以激发进一步的讨论或在我的情况下帮助其他人。 Still, I won't mark this as the answer because I find them more like a workaround than a proper solution.
不过,我不会将此标记为答案,因为我发现它们更像是一种解决方法而不是正确的解决方案。 They are to some extent based on the answers to this question (whose accepted answer I do not think it solves the problem).
它们在某种程度上是基于这个问题的答案(我认为它接受的答案不能解决问题)。
Solution using a dummy loop使用虚拟循环的解决方案
Here the idea is to fake a loop to have access to the continue
statement that allows you to jump to the end of function.这里的想法是伪造一个循环来访问允许您跳转到函数末尾的
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
This solution works, but it is very ugly because uses a for loop in a creative way that is clearly not what it was designed for.这个解决方案有效,但它非常丑陋,因为以一种创造性的方式使用 for 循环,这显然不是它的设计目的。
Solution using 2-level exception handling使用2级异常处理的解决方案
Here the idea is to define and use a general exception, and use it to translate the exception type to signal that something went wrong (but it was already handled) and then basically send the execution flow to the end.这里的想法是定义和使用通用异常,并使用它来转换异常类型以表示出现问题(但它已经被处理),然后基本上将执行流程发送到最后。
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.