【问题标题】:Catching Python runtime errors only仅捕获 Python 运行时错误
【发布时间】:2012-02-17 15:25:02
【问题描述】:

当我调用与shutil、http等系统库交互的代码时,我发现自己在没有指定异常类型的情况下处理异常,如果系统处于意外状态(例如文件锁定、网络不可用),所有这些都可能抛出等)

try:
    # call something
except:
    print("OK, so it went wrong.")

这让我很困扰,因为它还会捕获 SyntaxError 和其他基于程序员错误的异常,而且我已经看到了避免此类开放式异常处理程序的建议。

是否存在所有运行时错误都源自我可以在这里使用的一些常见异常基类的约定?或者任何不涉及语法错误、模块导入失败等的事情?即使KeyError 我也会考虑一个错误,因为如果我不能 100% 确定密钥会在那里,我倾向于使用 dict.get()。

我不想列出每一种可能的异常类型,尤其是因为我调用了很多我无法控制的支持代码。

更新:好的,答案让我意识到我问错了问题——我真正想知道的是是否有 Python 约定或明确建议库编写者使用特定的基础类为他们的例外,以便将他们与更平凡的SyntaxError 和朋友区分开来。

因为如果图书馆作者有一个约定,作为图书馆消费者,我可以对可能抛出的内容做出一般假设,即使具体情况可能会有所不同。不确定这是否更有意义?

UPDATE AGAIN:Sven 的回答终于让我明白,与其放弃和捕获顶层的一切,我可以在较低层处理和细化异常,因此顶层只需要从下面的级别担心特定的异常类型。

谢谢!

【问题讨论】:

  • 谢谢,我已经搜索过,但没有找到明确的答案。解析/语法/程序员错误和运行时错误之间的区别在哪里?
  • 请注意,您通常无法捕获SyntaxError——它会在编译源代码时被抛出,远在它执行之前。如果您的try 块包含importexecexecfile()eval(),则可以捕获SyntaxError 的唯一情况。
  • @SvenMarnach:嗯,我确信我已经看到这些无类型处理程序甚至可以捕获语法错误,但它可能是别的东西,更微妙。我手边没有一个干净的例子。谢谢指正。
  • @KimGräsman:SyntaxError 表示某些文件甚至无法解析,因此代码不可能开始执行 -- 另见stackoverflow.com/questions/1856408/…
  • 您可以在execeval() 上捕获SyntaxError,如果您正在导入的模块中存在语法错误,我也会考虑import

标签: python


【解决方案1】:
  1. 始终使try 块尽可能小。

  2. 仅捕获您要处理的异常。查看您正在处理的函数的文档。

这可确保您考虑可能会发生哪些异常,并考虑如果发生异常该怎么办。如果发生了您从未想过的事情,那么您的异常处理代码可能无论如何都无法正确处理这种情况,因此最好传播异常。

您说您“讨厌必须列出每一种可能的异常类型”,但通常情况还不错。打开文件?抓住IOError。处理一些库代码?他们通常有自己的异常层次结构和特定的顶级异常——如果你想捕获任何特定于库的异常,只需捕获这个。尽可能具体,否则错误迟早会被忽视。

关于 Python 中用户定义异常的约定:他们usually should be derived from Exception。这也是标准库中大多数用户定义的异常的来源,因此您至少应该使用

except Exception:

而不是一个简单的except 子句,它也捕获KeyboardInterruptSystemExit。正如您自己所指出的,这仍然会捕获许多您不想捕获的异常。

【讨论】:

  • 感谢明智的建议!我认为Exception 会让我遇到OverflowError 之类的问题,我也认为这是程序员错误。但是你关于库特定异常的注释让我思考——如果我可以连接我们所有的内部模块来抛出特定于库的异常,这将更容易处理。对于我已经完成此操作的模块,错误处理要简单得多。
【解决方案2】:

查看 Python 文档中的 built-in exceptions 列表。听起来您最想要的是抓住StandardError,尽管这也包括KeyError。还有其他基类,例如 ArithmeticErrorEnvironmentError,有时您可能会发现它们很有用。

我发现第三方库确实从Exception 派生了他们的自定义异常,如此处所述。程序员也倾向于在适当的情况下引发标准的 Python 异常,例如 TypeErrorValueError 等。不幸的是,这使得很难将库错误与源自Exception 的其他错误区分开来。我希望 Python 定义例如UserException 基类。一些库确实为它们的异常声明了一个基类,但您必须知道它们是什么,导入模块并显式捕获它们。

当然,如果你想捕获所有除了KeyErrorIndexError 以及脚本停止器异常,你可以这样做:

try:
    doitnow()
except (StopIteration, GeneratorExit, KeyboardInterrupt, SystemExit):
    raise    # these stop the script
except (KeyError, IndexError):
    raise    # we don't want to handle these ones
except Exception as e:
    handleError(e)

诚然,每次写起来都很麻烦。

【讨论】:

  • 很好,我没有想到明确地捕捉并重新提出我/不/想要捕捉的内容。
  • "我希望 Python 定义例如 UserException 基类。" ——这也是我所希望的。对于 Python 来说,这似乎是不典型的,它通常具有很强的约定。
【解决方案3】:

RuntimeError怎么样:http://docs.python.org/library/exceptions.html#exceptions.RuntimeError

如果这不是您想要的(而且很可能不是),请查看该页面上的例外列表。如果您对层次结构如何组合在一起感到困惑,我建议您花 10 分钟时间检查您感兴趣的异常的 __bases__ 属性,看看它们共享哪些基类。 (请注意,__bases__ 并没有在整个层次结构中封闭——您可能还需要检查超类基础)。

【讨论】:

  • “这个异常主要是以前版本的解释器的遗留物;它不再使用了。”
  • @kindall:链接页面有所有内置的异常,所以 OP 可以选择他喜欢的,你知道的。
  • 我知道 RuntimeError,但我还没有找到明确的建议库编写者将其用作所有运行时错误的基础......有这样的事情吗?
  • @Marcin;谢谢,但我想根本问题是我不知道我对什么类感兴趣。基本上我想捕捉除程序员错误之外的任何东西。有关更多信息,请参阅我的更新,希望有助于澄清。
猜你喜欢
  • 2010-10-23
  • 1970-01-01
  • 1970-01-01
  • 2013-09-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-15
  • 2011-02-04
  • 2015-09-29
相关资源
最近更新 更多