EAFP 与 LBYL 风格
EAFP 与 LBYL 是两种“防御性处理机制”,相信你一定接触过,只是可能没有深入思考过这个问题。
输入两个数,要输出相除后的结果:
a, b = map(int, input().split())
print(a / b)
但是b可以等于0,我们有两种检查方式:
# EAFP
try:
print(a / b)
except ZeroDivisionError: print('Error')
# LBYL
if b != 0:
print(a / b)
else: print('Error')
第一种风格叫做EAFP(Easier to Ask for Forgiveness than Permission),也就是“获得原谅比请求许可容易”,也就是不做检查,直接try,有问题再处理异常。
第二种风格叫做LBYL(Look Before You Leap),也就是“三思而后行",先排除错误,再执行代码。
除了除0检查外,再比如检查文件存在,检查字典是否存在键等....这种操作非常常见。实际上两种形式常常共存。
从效率上讲,try语句需要执行保留现场,堆栈解退等操作,肯定比if慢,但是LBYL每次都要做固定成本检查;理论上果发生异常并不多,则EAFP更优,反之LBYL更优。
编程语言内置结构往往倾向抛出异常(比如python访问空键的KeyError或者c++使用new失败时默认也是抛出异常),然后让用户自己解决。
在自己写代码时,python鼓励多使用EAFP和异常,这是由他的动态类型所决定的,你编写的函数可能适用于各种类型,你不知道它是什么,只要它有反馈就可以了,没有反馈再处理。同时python的异常系统很完善,包含了各种常见的错误,也很容易继承扩展自定义异常,有利于可读性。
而如果是c++,类型一般是严格的,大部分时候可以知道各个对象的细节,相对合理的做法是用LBYL直接处理“意料之中”的异常(比如你明知道除数是有0的,或者你知道要访问字典,而大部分时候是查询空键),而用try处理在调试时候发生在意料之外的异常。同时《Effective C++》里就提到过,在C++里不应该滥用try,因为在c++这样效率敏感的场合,try的检查和回溯非常慢,与if效率差距很大。