防御式编程
保护程序免造非法数据的破坏
- 检查所有来源于外部数据的值
这里需要注意的是数据值的范围,检查数据值在允许的范围内。如字符串,要确保其不超长。注意企图令缓冲区溢出的数据、注入SQL、注入的HTML或XML、整数溢出以及传递给系统调用的数据。 - 检查子程序所有输入参数的值
和检查外部数据一样,只不过现在数据来自于你自己写的程序而不是外部接口。 - 决定如何处理错误的输入数据
后文再说,但是防御的最佳方式是不要引入错误。 - 防止引入错误的方法
迭代式设计、编码前写伪代码、写代码前先写测试用例、低层设计检查。 - 防范看似微小的错误
先秦·韩非《韩非子·喻老》:“千丈之堤,溃于蚁穴,以蝼蚁之穴溃;百尺之室,以突隙之烟焚。
防范微小的错误得到的收益,可能比你想象中要大。
断言
断言对于大型复杂程序或可靠性要求极高的程序来说,尤其有用。
断言用于在代码中说明各种假定:
断言主要是用于开发和维护阶段。通常,断言只是在开发和维护阶段。通常,断言只是在开发阶段被编译到目标代码中,而在生成产品时并不编译进去。
使用断言的建议
- 用错误处理代码来处理预期会发生的状况,用断言来处理绝不应该发生的状况。
断言是用来检查永远不该发生的情况,触发了断言意味着应该修改程序的源代码了!把断言看做是可执行的注释。
list = [1, 2, 3, 4]
try:
user_choice = input('请输入>>>')
user_choice = int(user_choice)
except Exception:
print('输入错误')
else:
assert user_choice < len(list)
print(list[user_choice])
- 避免把需要执行的代码放在断言中
- 用断言来注解并验证前条件和后条件
契约式设计是一种编程思想。意思是调用方和被调用方之间要有契约精神。就像员工和老板。员工保证我身体健康,干活利索,老板保证定时发工资,不加班。
如果变量来自于外部应该用错误处理代码;如果变量的值来源于可信的系统内部,这些值不能超过合法范围,这时候就应该使用断言。 - 对于高健壮性的代码,应该先使用断言再处理错误
甚至可以同时用断言和错误处理代码来处理通一个错误。
错误处理技术
错误处理用于你可以预料到要发生的错误。
- 返回中立值
有时,处理错误数据的最佳做法就是继续执行操作并简单的返回一个没有危害的数值。
try:
num_one = 1
num_zero = 0
number = num_one/num_zero
except Exception:
number = 0
finally_num = number + 100 # 这样代码还是可以执行
print(finally_num)
- 换用下一个正确的数据
如果你以每秒100次的速度读取体温计的数据,那么如果某一次得到的数据有误,你只需要再读一次即可。 - 返回与前次相同的数据
你每秒读取100次温度计的温度数据,温度在0.01秒内也不会发生太多变化,所以用跟上次一样的读数也是可以滴。 - 换用最接近的合法值
比如倒车的时候,速度表并不会显示负数,而是显示0,也就是使用最接近的合法值。所以操作字符串时,如果发现莫个字符串的长度小于0,你也可以用0代替。 - 把警告信息记录到日志文件中
- 返回一个错误码
只让系统中的某些部分处理错误。
下层犯错,上层处理,下层只管报告。
那么下层程序如何打小报告呢?
- 设置状态变量
- 将状态值作为函数的返回值
- 抛出异常
- 调用错误处理子程序或对象
将错误处理的职责集中到一个人身上。所有人都得知道他是管事的,并且向他报告,就像宿舍的舍管。