Python assert

About

 

在没完善一个程序之前,我们不知道程序在哪里会出错,与其让它在运行最崩溃,不如在出现错误条件时就崩溃。

这时,就要用到断言assert了,Python中的断言语句格式用法很简单。

断言 assert 是指期望用户指定的条件满足,它是当用户定义的约束条件不满足时触发AssertionError异常,因此 assert 语句可以视为条件式的 raise 语句。它的主要功能是帮助程序员调试程序,从而保证程序运行的准确性,一般在开发调试阶段使用。

assert的使用

 

assert的一般用法

assert condition

assert判断条件(condition)是否成立,如果不成立,则抛出异常,逻辑上等同于:

if not condition:
    raise AssertionEerror()
    
a = ''
# assert a

if not a:
    raise AssertionError('a等于空')

assert的另一种形式

assert condition, expression

如果condition为False,就raise一个描述为expression的AssertionError的错误出来,逻辑上等同于:

if not condition:
    raise AssertionEerror(expression)

a = ''
# assert a, 'a是空的啦'

if not a:
    raise AssertionError('a等于空')

启用、禁用断言

 

首先,要知道Python解释器在运行时有两种模式:

  • 调试模式,该模式下,内置只读变量__debug__为True。
  • 优化模式,当使用选项-O运行时,即python.exe -O demo.py为优化模式,内置只读变量__debug__为False。
    来看示例,有Python文件内容是:
a = ''
# assert a, 'a是空的啦'

if not a:
    raise AssertionError('a等于空')

我们分别使用两种模式运行该文件,先来看正常的调试模式:

M:\>python testsss.py
Traceback (most recent call last):
  File "testsss.py", line 56, in <module>
    assert a, 'a是空的啦'
AssertionError: a是空的啦

此时上述Python文件在调试模式下,触发了assert条件执行,并引发AssertionError异常。
再来看优化模式:

M:\>python -O testsss.py
Traceback (most recent call last):
  File "testsss.py", line 59, in <module>
    raise AssertionError('a等于空')
AssertionError: a等于空

由报错内容可以发现,在调优模式下,断言语句被禁用,报错语句是我们手写if判断引发的。

一些建议

 

在调优模式下,在一定程度上提高了程序执行效率,但是这相当于埋下了一颗雷。
那么我们应该什么时候应该使用断言呢?一般的,如果没有特别的目的,断言应该用于:

  • 防御性的编程环境中。
  • 运行时对程序逻辑的检测。
  • 合约性检查,比如前置/后置条件检查。
  • 程序中的常量。
  • 检查文档。
  • 代码测试中。

当然,一些情况下,也不建议使用断言:

  • 不要用于测试用户提供的数据,或者那些需要在所有情况下需要改变检查的地方
  • 不要用于检查你认为在通常使用中可能失败的地方。断言用于非常特别的失败条件。你的用户绝不看到一个AssertionError,如果看到了,那就是个必须修复的缺陷。
  • 特别地不要因为断言只是比一个明确的测试加一个触发异常矮小而使用它。断言不是懒惰的代码编写者的捷径。
  • 不要将断言用于公共函数库输入参数的检查,因为你不能控制调用者,并且不能保证它不破坏函数的合约。
  • 不要将断言用于你期望修改的任何错误。换句话,你没有任何理由在产品代码捕获一个AssertionError异常。
  • 不要太多使用断言,它们使代码变得晦涩难懂。

最后的扩展

 

默认的,__debug__是常量,包括None、False、True这些常量不能重新赋值(即使作为属性名赋值给它们,也会引发SyntaxError),因此可以将它们视为“True”常量。

if __debug__:
    print('debug模式')

关于-O,在命令行的环境下,使用python.exe -O demo.py时,将会删除(可以理解为忽略)assert语句和任何基于__debug__值的代码。详见PEP 488
关于-OO,在命令行的环境下,使用python.exe -OO demo.py时,将会丢弃文档字符串。详见PEP 488

def foo():
    """ docstrings """
    pass

if __debug__:
    help(foo)

上述代码,使用python.exe demo.py会返回foo函数的文档信息。而使用python.exe -OO demo.py后,foo函数的文档信息将不会返回。

posted @ 2020-01-19 20:59  干it的小张  阅读(356)  评论(0编辑  收藏  举报