那么咱们何时应该使用断言呢?若是没有特别的目的,断言应该用于以下状况:测试
- 防护性的编程
- 运行时对程序逻辑的检测
- 合约性检查(好比前置条件,后置条件)
- 程序中的常量
- 检查文档
(断言也能够用于代码测试,用做一个作事毛手毛脚的开发人员的单元测试,只要能你接受当使用-O标志时这个测试什么都不作。我有时也会在代码中用"assert Fasle"来对尚未实现的分支做标记,固然我但愿他们失败。若是稍微更细节一些,或许触发NotImplementedError是更好的选择)优化
由于程序员是对于代码正确性表现出的信心不一样,所以对于何时使用断言的意见各不相同。若是你确信代码是正确的,那么断言没有任何意义,由于它们从不会失败,所以你能够放心地移除它们。若是你确信它们会失败(例如对用户输入的数据的检测),你不敢用断言,这样编译就能经过,但你跳过了你的检查。编码
在以上两种状况之间的状况就显得特别有趣了,那就是当你相信代码是正确的,但又不是特别肯定的时候。或许你忘记了一些奇怪的边角状况(由于咱们都是人),在这种状况下,额外的运行时检查将帮助你尽量早地捕获错误,而不是写了一大堆代码以后。设计
(这就是为何使用断言的时机会不一样。由于咱们对代码正确性的信息不一样,对于一我的有用的断言,对于另外一我的来讲倒是无用的运行时测试。)code
另外一个断言用得好的地方就是检查程序中的不变量。一个不变量是一些你能相信为真的条件,除非一个缺陷致使它变成假。若是有一个缺陷,越早发现越好,所以咱们须要对其进行测试,但咱们不想由于这些测试而影响代码执行速度。所以采用断言,它能在开发时生效而在产品中失效。
一个关于不变量的例子多是这样的状况。若是你的函数在开始的时候指望一个打开的数据库链接,而且在函数返回后该数据库链接依然是打开的,这是一个函数的不变量:
断言也是一个很好的检查点注释。为了替代以下注释:
#当咱们执行到这里,咱们知道n>2
你能够确保在运行时用如下断言:
断言也是一种防护性的编程形式。你不是在防范当前代码发生错误,而防范因为之后的代码变动发生错误。理想状况下,单元测试应该直到这个做用,可是让咱们面对这样一个现实:即便存在单元测试,他们在一般状况下也不是很完备。内建的机器人可能没有工做,但数周以来也没有人注意到它,或者人们在提交代码以前忘记了执行测试。内部检查将是防止错误渗入的另外一道防线,尤为对于那些悄悄地失败,但会引发代码功能错误并返回错误结果的状况有效。
假设你有一系列的if...elif代码块,你预先知道变量指望的值:
假设这段代码如今彻底正确。但它会一直正确吗?需求变动,代码变动。若是需求变为容许target = w,并关联到run_w_code,那将会发生什么状况?若是咱们变动了设置target的代码,可是忘记了改变这个代码块,它就会错误地调用run_z_code(),错误就会发生。对于这段代码最好的方法就是编写一些防护性的检查,这样它的执行,即便在变动之后,要么正确,要么立刻失败。
在代码开始添加注释是个好的开端,可是人们都不太喜欢读和更新这些注释,这些注释会很快变得过期。但对于断言,咱们能够同时对这块代码编写文档,若是这些断言被违反了,会直接引发一个简单而又直接的失败。
这里的断言同时用于防护性编程和检查文档。我认为这是最优的解决方案:
这诱使开发者去不理代码,移除像value ==c这类没必要要的测试,以及RuntimeError的“死代码”。另外,当"unexpected error"错误发生时这个消息将很是窘迫,确实会发生。
合约式设计是断言另外一个用得好的地方。在合约式设计中,咱们认为函数与其余调用者遵循合约,例如像这样的状况:
“若是你传给我一个非空字符串,我保证返回转换成大写的首字母。”
若是合约被破坏了,不论是被函数自己仍是调用者,这都会产生缺陷。咱们说这个函数须要有前置条件(对指望的参数的限制)和后置条件(对返回结果的约束)。所以这个函数多是这样的:
合约式设计的目的是,在一个正确的程序里,全部的前置条件和后置条件都将获得处理。这是断言的经典应用,自(这个想法持续)咱们发布完好陷的程序而且将其放入产品,程序将是正确的而且咱们能够放心地移除检查。
这里是我建议不使用断言的状况:
*不要用于测试用户提供的数据,或者那些须要在全部状况下须要改变检查的地方
*不要用于检查你认为在一般使用中可能失败的地方。断言用于很是特别的失败条件。你的用户毫不看到一个AssertionError,若是看到了,那就是个必须修复的缺陷。
*特别地不要由于断言只是比一个明确的测试加一个触发异常矮小而使用它。断言不是懒惰的代码编写者的捷径。
*不要将断言用于公共函数库输入参数的检查,由于你不能控制调用者,而且不能保证它不破坏函数的合约。
*不要将断言用于你指望修改的任何错误。换句话,你没有任何理由在产品代码捕获一个AssertionError异常。
*不要太多使用断言,它们使代码变得晦涩难懂。