assert
最近在读别人代码的时候发现了好多自己当时学python的时候没有学过的东西
语法
Python assert用于判断一个表达式,在表达式条件为false的时候触发异常。
语法格式如下:
1 | assert expression |
等价于
1 | if not expression: |
后面也可以跟参数:
1 | assert expression [, arguments] |
等价于:
1 | assert expression [, arguments] |
使用实例
检查 先验条件 使用assert,检查 后验条件 使用 异常处理
举个例子来说明一下,在开发中我们经常会遇到读取本地文件的场景。我们定义一个read_file方法。
1 | def read_file(path): |
read_file函数要求在开始执行的时候满足一定条件:file_path必须是str类型,这个条件就是*先验条件*,如果不满足,就不能调用这个函数,如果真的出现了不满足条件的情况,证明代码中出现了bug,这时候我们就可以使用assert语句来对file_path的类型进行推断,提醒程序员修改代码,也可以使用if...raise...语句来实现assert,但是要繁琐很多。在很多优秀的Python项目中都会看到使用assert进行先验判断的情况,平时可以多多留意。
read_file函数在被调用执行后,依然需要满足一定条件,比如file_path所指定的文件需要是存在的,并且当前用户有权限读取该文件,这些条件称为后验条件,对于后验条件的检查,我们需要使用异常来处理。
1 | def read_file(file_path): |
文件不存在和没有权限,这两种情况并不属于代码bug,是代码逻辑的一部分,上层代码捕获异常后可能会执行其他逻辑,因此我们不能接受这部分代码在生产环境中被忽略,这属于*后验条件*。并且,相比于assert语句只能抛出AssertionError,使用异常可以抛出更详细的错误,方便上层代码针对不同错误执行不同的逻辑。
再比如
1 | import sys |
其他异常处理
顺手补一下其他异常处理
try...except
这个语句主要是用来可能发生错误的语句里面,比如在跑一个循环的时候有的除以零,有的没有除以零,可以使用try except把除以零的赋值nan避免这个循环停止,让程序继续跑下去。
try...finally
1 | # try..finally模式 |
try..finally模式是:
- 没有异常就先运行try所有语句,再运行finally所有语句.
- 要是有异常,try执行到异常就跳到finally,然后直接跳出将异常递交给上层的try.控制流并不通过所有try语句.
- finally能跟在except/else后,优先先执行except/else再执行finally.
由此可知, try…finally 模式更适合于嵌套在try..except内作为保证某些代码一定执行.因为try..except…else要是执行了except就不会执行else,无法保证某个代码必须执行.所以常见的整合模式为:
1 | # 两种模式的嵌套和结合 |
PS: 要是finally在except/else前面肯定会报错.因为try后直接给finally,然后会交给上层try.但没有上层try…
实例:
1 | #!/usr/bin/python |
raise
与try一起使用
raise语句可以很好地用于抛出某个异常从而被try捕获. 更常用于结合if等进行条件检查.例如某变量假定[0,10],<0时抛出一个错,>10抛出另一个错误.
raise一般是raise exception,args
,args一般采用一个值,来初始化异常类的args属性,也可以直接使用元组来初始化args.
1 | raise <name> #手工地引发异常 |
参考资料
https://stackoverflow.com/questions/40182944/difference-between-raise-try-and-assert
https://www.cnblogs.com/lsdb/p/11063568.html
https://blog.csdn.net/qq_29287973/article/details/78053764
https://www.runoob.com/python3/python3-assert.html
https://zhuanlan.zhihu.com/p/91853234