podBayDoorStatus = 'open'
assert podBayDoorStatus == 'open', 'The pod bay doors need to be "open".'
这里将 podBayDoorStatus
设置为 open
,所以从此以后,
更充分期望这个变量的值是 open
。在使用这个变量的程序中,
基于这个值是 open
的假定,可能写下了大量的代码,
即这些代码依赖于它是 open
,才能按照期望工作。
所以添加了一个断言,确保假定 podBayDoorStatus
是 open
是对的。
这里,加入了信息 'The pod bay doors need to be "open".'
, 这样如果断言失败,就很容易看到哪里出了错。
然后,假如犯了一个明显的错误,
把另外的值赋给 podBayDoorStatus
。
这个断言会抓住这个错误,清楚地告诉出了什么错。
podBayDoorStatus = 'I\'m sorry, Dave. I\'m afraid I can\'t do that.'
# assert podBayDoorStatus == 'open', 'The pod bay doors need to be "open".'
market_2nd = {'ns': 'green', 'ew': 'red'}
mission_16th = {'ns': 'red', 'ew': 'green'}
这两个变量将针对 Market
街和第2街路口,
以及 Mission
街和第16街路口。作为项目启动,
希望编写一个 switchLights()
函数,
它接受一个路口字典作为参数,并切换红绿灯。
开始可能认为, switchLights()
只要将每一种灯按顺序切换到下—种顔色:
'green'
值应该切换到 'yellow'
, 'yellow'
应该切换到 'red'
,
'red'
应该切换到'green'
。实现这个思想的代码看起来是这样:
def swithLights(stoplight):
for key in stoplight.keys():
if stoplight[key] == 'green':
stoplight[key] = 'yellow'
elif stoplight[key] == 'yellow':
stoplight[key] = 'red'
elif stoplight[key] == 'red':
stoplight[key] = 'green'
# assert 'red' in stoplight.values(), 'Neither light is red! ' + str(stoplight)
swithLights(market_2nd)
可能已经发现了这段代码的问题,但假设编写了剩下的模拟代码,
有几千行,但没有注意到这个问题。当最后运行时,
程序没有崩溃,但虚拟的汽车撞车了!因为已经编写了剩下的程序,
所以不知道缺陷在哪里。也许在模拟汽车的代码中,
或者在模拟司机的代码中。可能需要花几个小时追踪缺陷,
才能找到 switchLights()
函数。
但如果在编写 switchLights()
时,添加了断言,
确保至少一个交通灯是红色,可能在函数的底部添加这样的代码:
assert 'red' in stoplight.values(), 'Neither light is red! ' + str(stoplight)
def swithLights(stoplight):
for key in stoplight.keys():
if stoplight[key] == 'green':
stoplight[key] = 'yellow'
elif stoplight[key] == 'yellow':
stoplight[key] = 'red'
elif stoplight[key] == 'red':
stoplight[key] = 'green'
assert 'red' in stoplight.values(), 'Neither light is red! ' + str(stoplight)
下面的语句多运行几遍,然后才会发现问题:
# for ii in range(100):
# print(ii)
# swithLights(market_2nd)
在实际情况中,很可能多次运行也没有问题,但程序会在某次运行时出错。 有了断言,程序就会崩溃,并提供出错。
这里重要的一行是 AssertionError()
。
虽然程序崩溃并非所愿,但它马上指出了逻辑失败:两个方向都没有红灯,
这意味着两个方向的车都可以走。
在程序执行中尽早快速失败,可以省去将来大量的调试工作。
断言与“异常”用法的区别
断言不像异常,代码不应该用 try
和 except
处理 assert
语句。
如果 assert
失败,程序就应该崩溃。
通过这样的快速失败,产生缺陷和第一次注意到该缺陷之间的时间就缩短了。
这将减少为了寻找导致该缺陷的代码,而需要检查的代码量。
断言针对的是程序员的错误,而不是用户的错误。
对于那些可以恢复的错误(诸如文件没有找到,或用户输入了无效的数据),
请抛出异常,而不是用 assert
语句检测它。
禁用断言
在运行 Python 时传入 -O
选项,可以禁用断言。
如果已完成了程序的编写和测试,不希望执行逻辑检测,
从而减慢程序的速度,这样就很好(尽管大多数断言语句所花的时间,不会察到速度的差异)。
断言是针对开发的,不是针对最终产品。 当将程序交给其他人运行时,它应该没有缺陷,不需要进行逻辑检查。