2

最佳实践似乎是assert用于在代码正确的情况下永远不会发生的条件,以及用于有点不寻常但可能发生的条件的异常(例如,当内存用完或用户输入无效时,或者外部连接断开)。我理解这种做法背后的基本原理如下:

  1. assert将使用 -O 解释器标志禁用。不能允许由外部因素引起的条件被默默地忽略,所以断言有不合适的。OTOH,只有在我的代码不正确时才可能出现的情况有望通过测试和调试消除,所以assert很好。

  2. assert阻止调用者处理异常,因为AssertionError通常被解释为“不要抓住我,这是一个灾难性的失败”。此外,它太笼统而无法捕捉。当发现错误时,这是​​完美的;对此的典型处理是停止执行并调试代码。如果是外部原因导致的常见情况,那就不好了。

假设我编写了一些代码来确保某个函数参数始终为正。如果我发现它是否定的,显然我在代码中犯了一个错误。因此,我assert认为这个论点是积极的。

后来,有人发现这个功能在另一个应用程序中很有用。他们导入它,并向它发送各种数据。现在从我的功能的角度来看,实际上很有可能收到负值;它只是一个无效的用户输入。可以说,assert不再合适,应该用例外替换。

由于几乎任何代码都有可能在某一天被重用,而且通常在我不知情的情况下,这个论点似乎在说“从不使用assert;只使用异常”。显然,这不是公认的做法。我错过了什么?

编辑:

更具体地说,假设该函数根本无法处理否定参数。因此,一旦参数为负,该函数将执行以下操作之一:

  • 引发异常
  • 断言失败
  • 继续执行,可能产生不正确的输出

我可以看到,如果调用者捕捉到否定论点,那该有多好。但是,如果对函数的调用散布在代码周围的几十个地方,那么由于多次重复相同的检查,这可能会损害代码的清晰度。(更不用说,它可能会不小心忘记。)

4

2 回答 2

2

如果您正在编写/重用的函数对正数或负数有效,则它不是应该包含断言的方法。调用重用函数的函数应该有断言,因为它是向函数提供无效值的函数。

function x() {
   var i;
   // logic to set i. use assertion to test the logic.
   assert(i > 0);
   reusedFunc(i);
}

如果reusedFunc(i) 对负数无效,则如果传递一个负值,它应该抛出异常。

于 2012-04-04T20:58:56.033 回答
1

assert语句用于您在开发和调试代码时使用的东西,而不是保证关键的 API 约束。

对于您的正数示例,ValueError如果在代码中使用负值会产生不良后果,请测试该值并使用有用的错误消息引发。

告诉人们永远不要使用断言语句。它们很容易写,但它们往往不合适。

assert当人们写很长的语句并决定使用括号使语句和消息跨越多行时,语句也会失败......这SyntaxWarning会在现代 Python 中生成一个关于作者通过使用 (condition, message) 无意中创建的元组-function 声明,但并非总是如此。

另一个经验法则:如果你看到一个单元测试验证 anAssertionError被提出,那么代码不应该使用断言。

如果你不使用assert语句,这些东西都不会咬你。

于 2012-04-06T01:41:12.580 回答