概述
0、什么是断言(assertion)
断言是一个调试工具。它用于发现异常,而不是用于处理异常。
记住这句话,它是断言的核心意义。只有理解这句话,才能正确地使用断言。我们将会在最后一小节深入探讨这个问题。
Python3中,使用assert语法来声明一个断言,其语法格式如下:
assert bool_expr, optional_expr
如果bool_expr的估值(表达式的最终计算结果)为False,系统就会抛出一个AsesertionError异常。这个异常包含了必要的栈信息,所以它能够为解决这个“意外”提供很多的信息。
如果提供了可选的optional_expr,则optional_expr是异常AsesertionError的构造函数参数。optional_expr可为异常提供了额外的信息,所以它是非常有用的。
1、一个例子
我们知道,人类的生理性别只有两种,即男性和女性(No offence to GLBTQ)。假如我们定义了一个Human的类,其中有gender属性,那么这么属性必须是Male或者Female其中之一,而不能是其它值。程序在实际的运行过程中,gender属性偶尔会意外地被初始化为非法的值,那么在开发测试过程中,我们就可以使用assert语句来帮我们定位问题。
class Gender:
Male = 1 # 男
Female = 2 # 女
@classmethod
def IsValid(cls, val):
if val in (cls.Male, cls.Female):
return True
return Fale
class Human:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
assert Gender.IsValid(gedner), "Invalide Gender:{}".format(gender)
assert age >= 0, "Invalide age:{}".format(age)
在创建Human对象时,如果遇到意外性别或者年龄,程序就会抛出一个AsseritonError,并中断程序(如果没有捕获处理的话)。
2、怎么关闭assert
正如第0节所说的,assertion是一个调试工具,在功能开发并测试完毕之后,正式发布之前,应该先把assertion语句全部去掉(或者使其失效)。在C++中,assert语句在release版本中是一个空语句,在编译阶段就可以被处理。但在Python3是脚本语言,所以我们需要用不同的方式来处理。
第一种是通过给python解析器传递-O参数,其实命令形式如下:
python -O program.py
另外一种,也是比较直观和暴力的方法,就是直接注释(或者删除)所有的assert语句。
3、如何用好assert(assert的目的)
断言是一个调试工具。它用于发现异常,而不是用于处理异常。
我们公司有一个C++面试题,其内容大概如下:
// 实现函数ReverseStr,将参数str所代表的字符串反转
void ReverseStr(char * str);
其中大概有10%的面试者会在第一行代码就直接用一个assert语句,来判断str是否为NULL。其代码大抵如下:
void ReverseStr(char * str)
{
assert(NULL != str);
// 其余代码
}
而当我问其为什么使用assert,而不是一个if语句的时候,没有人能给出正确的解释。不过结果也不出意思,能在此处使用assert的人,就说明他不理解assert是什么。这也是我为什么会增加这一个小节内容的原因。
在实际开发过程中,难免会出现一些意想不到的问题。有些问题会产生严重的后果,产生非常易于发现的错误,或者直接使程序挂掉。这种越noisy的错误,越容易被发现,往往也越容易处理。但一些错误,它并不会产生明显的错误,往往程序也能“正常地”继续执行;而往往就是这类错误,会让人崩溃。
异常处理是程序开发过程中非常正常的形象。但是,如果无论什么地方都进行异常处理,程序就会显得非常庞大而冗余,而且没有必要。我们会在确保一定会出错(被错误使用)的地方做异常处理;而那些逻辑上(理论上、设计上)不会出错的地方,就不需要。
而我们使用assert的大部分时候,就是用来监测那些逻辑上不会出错的地方可能发生的异常。如果监测到了,应该是修改设计,修复BUG,或者增加必要的异常处理。
所以我们使用assert,是用来发现意料之外的异常,而不是用来做异常处理。也就是说,这是一个使用意料之外的错误noisy的工具。如果我们定位到了问题,应该进行功能或者设计上的修改,来修复这个问题。
我们现回头看看本节开头提到的问题,“上纲上线”地讨论一下aasert到底应该怎么使用。由于C++中assert的目的与Python的一致,为了方便讨论,这里直接使用了C++代码。
void ReverseStr(char *str)
{
if (NULL == str)
{
// str传入NULL,是一个意料之中的“错误”,我们应该直接处理它
// 严格意义上来说,这个处理也是功能的一部分
return;
}
int len = strlen(str);
// 如果一个字符串的长度过长,可能会是一个错误,其中有种可能是str未以0结尾;
// 或者由于其它不可描述的原因导致
// 如果逻辑上,len不可能大于10240,但莫名地出现这种情况,我们就可以使用asser来定位问题了
// 在release版本中,下面的语句将会是一个空语句,因为它不是这个函数实现的一部分。
assert(len < 10240);
// 余下的代码
}
在这个例子中,if语句用于“错误”(异常)处理,它是功能的一部分,会一直存在。而assert语句用于发现异常,在我们解决了这个异常之后,我们就会让assert语句失效(去掉代码,或者借助于编译器)。
4、多说一句
assert是调试工具之一,而非全部。
每个类型的问题,会用到不同类型的调试工具。
最后
以上就是成就钢笔为你收集整理的python assert 不退出_Python3 基础:断言assert的全部内容,希望文章能够帮你解决python assert 不退出_Python3 基础:断言assert所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复