【问题标题】:How to execute something if any exception happens如果发生任何异常,如何执行某事
【发布时间】:2011-05-08 06:49:29
【问题描述】:

一个python新手问题:我需要做以下事情

try:
  do-something()
except error1:
  ...
except error2:
  ...
except:
  ...
#Here I need to do something if any exception of the above exception was thrown.

我可以设置一个标志并执行此操作。但是有没有更清洁的方法呢?

【问题讨论】:

  • 设置标志有什么不干净的地方?我的意思是,if 声明通常被认为是无害的......
  • +1 表示标志。否则,您会将事情与额外的嵌套级别混淆。也许有更好的方法来构建代码流,所以你根本不需要这样做
  • @detly 旗帜有什么不干净的地方?很容易误操作。如果您可以使用结构化替换标志解决方案,这通常是一种改进。所以,是的,如果没有其他捷径,那么标志可能是一种正确的方法,但这是最后的手段。
  • 相关:How to determine if an exception was raised once you're in the finally block?(注意:我还选择了一个标志作为最佳选择)

标签: exception-handling python


【解决方案1】:

您可以使用嵌套的try. 执行此操作。外部tryexcept 块应捕获所有异常。它的主体是另一个try,它立即重新引发异常。内部tryexcept 块实际上处理各个异常。您可以使用内部 try 中的 finally 块来做您想做的事情:在任何异常之后运行某些东西,但只能在异常之后运行。

这是一个小的交互式示例(出于怀旧目的以 Applesoft BASIC 为模型)。

try:
    input("]")  # for Python 3: eval(input("]"))
except:
    try:
       #Here do something if any exception was thrown.
       raise
    except SyntaxError:
       print "?SYNTAX",
    except ValueError:
       print "?ILLEGAL QUANTITY",
    # additional handlers here
    except:
       print "?UNKNOWN",
    finally:
       print "ERROR"

【讨论】:

    【解决方案2】:

    我刚刚尝试了几个不同的想法,看起来旗帜是你最好的选择。

    • 只有在没有异常的情况下才会调用其他套件
    • finally 总会被调用

    【讨论】:

    • 最好设置在 else 子句中。
    【解决方案3】:

    实际上,我不喜欢标志并将它们视为最后的解决方案。在这种情况下,我会考虑这样的事情:

    def f():
      try:
        do_something()
      except E1:
        handle_E1()
      except E2:
        handle_E2()
      else:
        return
      do_stuff_to_be_done_in_case_any_exception_occurred()
    

    当然,如果您可以在else: 的情况下返回,这只是一个选项。

    另一种选择可能是重新抛出异常并重新捕获它以更一般地处理错误。这甚至可能是最干净的方法:

    def f():
      try:  # general error handling
        try:  # specific error handling
          do_something()
        except E1:
          handle_E1()
          raise
        except E2:
          handle_E2()
          raise
      except (E1, E2):
        do_stuff_to_be_done_in_case_any_exception_occurred()
    

    【讨论】:

    • 意见不一......这比简单的旗帜丑多了,如果你问我的话。
    • 我喜欢您的第一个示例,并且很可能更喜欢在适用的情况下使用标志。第二,我必须同意@wim
    • @corvus 当我写下我不喜欢标志时,这并不是纯粹的个人喜好。还有一些客观原因(他们在 CS 中教授)来避免它们,例如代码 sn-ps 的状态性和封装。在管理标志变量(特别是如果你有几个)中引入错误(在开发或编译时没有注意到的错误)比你坚持正确的模式要容易得多。
    • @Alfe 你的观点很好。感谢您的观点。
    • 同意这些标志,如果do_stuff_... 很复杂,这是一个很好的解决方案,否则我认为将它写在每个except 子句中更具可读性。
    【解决方案4】:

    这是我能想到的最好方法。不过看起来有点代码味道

    try:
      exception_flag = True
      do-something()
      exception_flag = False
    except error1:
      ...
    except error2:
      ...
    except:
      ...
    finally:
      if exception_flag:
        ...
    

    如果您不在处理程序中重新引发异常,则不需要finally

    【讨论】:

      【解决方案5】:

      来自文档:http://docs.python.org/reference/compound_stmts.html#finally

      如果 finally 存在,它指定一个“清理”处理程序。执行 try 子句,包括任何 except 和 else 子句。如果任一子句发生异常且未处理,则暂时保存该异常。 finally 子句被执行。如果有一个保存的异常,它会在 finally 子句的末尾重新引发。如果 finally 子句引发另一个异常或执行 return 或 break 语句,则保存的异常将丢失。在 finally 子句执行期间,程序无法获得异常信息。

      【讨论】:

      • 即使有 no 异常,finally 子句的主体也会执行。我认为这不是 OP 想要的。
      • 是的。 finally 将始终执行。我想要与其他相反的东西。
      【解决方案6】:

      不清楚是否需要对error1、error2等进行不同的处理。如果不需要,那么下面的代码就可以了:

      try:
          do_something()
      except (error1, error2, error3), exception_variable:
          handle_any_of_these_exceptions()
      

      如果您确实需要以不同的方式处理不同的错误以及拥有通用代码,那么在 except 块中,您可以拥有以下类型的代码:

          if isinstance(exception_variable, error1):
             do_things_specific_to_error1()
      

      【讨论】:

      • 我需要做不同的事情。使用 isinstance 看起来像 unpythonic,但绝对是一种选择。
      • @amit 我一般同意isinstance 是一件坏事,但except 仅根据它们的类型隐含地使用它。我觉得这里合适。
      【解决方案7】:

      我认为通过在 try 子句中使用 return 是一个更简洁的解决方案。 如果一切正常,我们将返回在bar() 中获得的值。如果我们得到一个异常,我们将运行下一个代码,在这种情况下引发另一个异常。 用randint 演示。

      import random
      
      def foo():
          try:
              return bar()
          except IndexError:
              print('Error.')
          raise KeyError('Error msg')
          
      def bar():
          res = random.randint(0, 2)
          if res == 0:
              raise IndexError
          return res
      
      res = foo()
      print(res)
      

      【讨论】:

        猜你喜欢
        • 2014-05-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-08
        • 1970-01-01
        • 1970-01-01
        • 2017-08-19
        • 1970-01-01
        相关资源
        最近更新 更多