【问题标题】:Handling all but one exception处理除一个异常外的所有异常
【发布时间】:2013-04-13 23:06:46
【问题描述】:

如何处理除一个异常之外的所有异常?

try:
    something
except <any Exception except for a NoChildException>:
    # handling

类似这样,除了不破坏原始回溯:

try:
    something
except NoChildException:
    raise NoChildException
except Exception:
    # handling

【问题讨论】:

  • 简单回答:不要。捕获所有异常确实是一种不好的做法,因为您会倾向于捕获您无意捕获的异常,从而掩盖错误。这样做的合法案例很少。
  • 您似乎已经回答了自己的问题。告诉我们您对自己拥有的东西不满意的原因。
  • @Robᵩ 不完全是,他的示例会产生 new 异常,而不是重新引发旧异常。
  • @Lattyware 捕获所有异常没有问题 - 例如添加额外的上下文然后重新加注。但是,吞下所有异常(如本例所示)是不好的做法。

标签: python exception exception-handling error-handling


【解决方案1】:

Python 新手......但这不是一个可行的答案吗? 我使用它并且显然有效....并且是线性的。

try:
    something
except NoChildException:
    assert True
except Exception:
    # handling

例如,我用它来摆脱(在某些情况下无用的)从 os.mkdir 返回异常 FileExistsError。

那是我的代码是:

try:
  os.mkdir(dbFileDir, mode=0o700)
except FileExistsError:
  assert True

我只是接受目录无法以某种方式访问​​的事实作为中止执行。

【讨论】:

    【解决方案2】:

    答案是简单地做一个裸raise

    try:
        ...
    except NoChildException:
        # optionally, do some stuff here and then ...
        raise
    except Exception:
        # handling
    

    这将重新引发上次抛出的异常,原始堆栈跟踪完好无损(即使它已被处理!)。

    【讨论】:

    • 我同意。但我明白了:失败:您的 Patient.update 方法在不应该出现的情况下捕获了 ZeroDivisionError 类型的异常。永远不要在代码中使用裸 except 子句。仅捕获引发的 NoChildExceptions。而不是这个:成功忽略引发的类型异常:ZeroDivisionError 成功忽略引发的类型异常:NameError 成功忽略引发的类型异常:AttributeError 成功忽略引发的类型异常:TypeError 成功忽略引发的类型异常:ValueError 成功捕获引发的 NoChildException 测试已完成
    • @IvanVulović 所以你想要的是 捕捉NoChildExceptions(这与你所要求的完全相反),所以只做try: ... except NoChildException: ...,不需要任何花哨的东西。
    • 另外:永远不要except e/raise e。这吞噬了堆栈跟踪。
    【解决方案3】:

    我发现了一个上下文,在这个上下文中捕获所有错误但有一个并不是一件坏事,即单元测试。

    如果我有方法:

    def my_method():
       try:
          something()
       except IOError, e:
          handle_it()
    

    然后它可能有一个看起来像这样的单元测试:

    def test_my_method():
       try:
          my_module.my_method()
       except IOError, e:
          print "shouldn't see this error message"
          assert False
       except Exception, e:
          print "some other error message"
          assert False
       assert True
    

    因为您现在已经检测到 my_method 刚刚抛出了意外的异常。

    【讨论】:

    • 嗯,不。如果您不希望测试中有任何异常,请不要捕获任何异常。如果您确实期望它,请使用 with self.assertRaiseswith pytest.raises 并在上下文管理器之外断言。
    • 您假设 pytest 作为框架。错误的假设。
    • 不,我不是。 self.assertRaises 是单元测试(stdlib)。而且现在不推荐使用nosetests,pytest 可能是最常见的测试框架。
    • 我认为nose2.readthedocs.io/en/latest 的人们听到您的弃用声明会非常惊讶。特别是因为 Python 不弃用第三方库,这会问一个问题,“被谁弃用?” .另外,由于没有对 Python 开发人员进行过调查,我会非常犹豫地说哪个是最受欢迎的,尤其是在成熟产品中。并且回到您错过并且assertRaises没有解决的测试的原始点,是测试handle_it()是否正确处理异常
    • FWIW,我的观点甚至适用于鼻子跑者 - 您提到的新项目中有 nose.tools.assert_raises 和新项目中的 nose2.tools.such.helper.assertRaises
    【解决方案4】:

    我会将此作为对已接受答案的改进。

    try:
        dosomestuff()
    except MySpecialException:
        ttype, value, traceback = sys.exc_info()
        raise ttype, value, traceback
    except Exception as e:
        mse = convert_to_myspecialexception_with_local_context(e, context)
        raise mse
    

    此方法通过在捕获 MySpecialException 时维护原始堆栈跟踪来改进已接受的答案,因此当您的顶级异常处理程序记录异常时,您将获得指向原始异常抛出位置的回溯。

    【讨论】:

    • 这适用于旧版本的 Python,但现在它是 SyntaxError
    猜你喜欢
    • 1970-01-01
    • 2016-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-10
    • 2012-05-20
    相关资源
    最近更新 更多