仅捕获Python运行时错误

时间:2012-02-17 15:25:02

标签: python

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

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

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

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

我不想列出每一个可以想到的异常类型,特别是因为我调用了许多我无法控制的支持代码。

更新好的,答案让我意识到我提出了错误的问题 - 我真正想知道的是,是否有Python惯例或明确推荐为图书馆作者使用特定的基类来处理他们的例外情况,以便将他们与更普通的SyntaxError&朋友。

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

再次更新:Sven的回答最终让我明白,不是放弃并抓住顶层的所有内容,我可以在较低级别处理和优化异常,因此顶级只需要担心以下级别的特定异常类型。

谢谢!

3 个答案:

答案 0 :(得分:6)

  1. 始终使try块尽可能小。

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

  3. 这可以确保您考虑可能发生的异常,并考虑如果发生异常,该怎么做。如果您从未想过会发生某些事情,那么您的异常处理代码可能无法正确处理该情况,因此异常传播会更好。

    你说你“讨厌必须列出每一个可以想象的异常类型”,但通常并没有那么糟糕。打开文件?抓住IOError。处理一些库代码?它们通常具有自己的异常层次结构,并具有特定的顶级异常 - 如果要捕获任何特定于库的异常,只需捕获此异常。尽可能具体,否则错误迟早会被忽视。

    关于Python中用户定义的异常的惯例:他们usually should be derived from Exception。这也是标准库中大多数用户定义的异常所源自的,所以至少应该使用

    except Exception:
    

    而不是裸except子句,它也会捕获KeyboardInterruptSystemExit。正如您已经注意到的那样,这仍然可以捕捉到许多您不想捕捉的例外情况。

答案 1 :(得分:5)

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

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

当然,如果您想要捕获除了 KeyError以及IndexError以及脚本停止异常之外的所有内容,您可以这样做:

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)

不可否认,每次写作都变得麻烦。

答案 2 :(得分:1)

RuntimeErrorhttp://docs.python.org/library/exceptions.html#exceptions.RuntimeError

怎么样?

如果那不是您想要的(并且可能不是),请查看该页面上的例外列表。如果您对层次结构如何组合感到困惑,我建议您花十分钟时间检查您感兴趣的例外的__bases__属性,以查看它们共享的基类。 (请注意,__bases__并未在整个层次结构中关闭 - 您可能还需要检查超类基数。)