LBYL与EAFP漫谈

LBYL 的意思是“Look before you leap.” 指在程序执行之前做好检查。比如下面这段代码

if "key" in my_dict:
    x = my_dict["key"]
else:
    # handle missing key

EAFP 的意思是“Easier to ask for forgiveness than permission.” 在编程方面指的是相信程序会正确执行,如果出错了再处理错误,比如上面这段代码用 EAFP 风格写就是下面这样:

try:
    x = my_dict["key"]
except KeyError:
    # handle missing key

很多情况下,两种方式的写法是可以互相替换的,但是 Python 鼓励 EAFP
。原因是这种方法的可读性更高,速度也更快(只有在出错的时候才需要处理,而 LBYL 需要每次运行都检查)。

现在的大多数语言都有异常处理机制了,比如 Java, Python, Ruby 等,没有异常处理机制的都是一些古老的语言,比如 C 语言。但是没有异常处理机制并不代表程序总能运行正确,所以 C 语言需要其他形式来处理程序(函数)不能正确运行的情况,一般的方法是返回 0
表示运行正常,其他值表示运行异常。

但是这种处理形式有两个缺点(这部分可以参考《代码之髓》这本书的第 6 章):第一是可能遗漏错误。比如一个函数在大部分情况下都能正确运行,只有在很少的情况下会出错,或者只有改变了环境之后才会出错。那么很可能程序员会默认这个函数总是正确的,而忘记处理这个异常。如果是 Java 的话,程序员就必须在调用函数的地方处理掉所有可能的异常(虽然很多 Java 程序员喜欢不优雅地用 RuntimeError 处理所有的异常)。更让人头疼的事情是,一旦这“极少数”的情况发生了,那么错误经常不在错误出现的地方,而在很外层的一个调用处。你要花很多时间调试才能找到最终出错的地方。如果有异常处理机制的话,异常栈通常会直接给出 Exception 发生的地方。

第二个缺点是会使代码的可读性下降。因为要检查函数的返回值,要写很多 if-else
,程序真正的逻辑就变得难以阅读。我记得有位高人说过这么一句话,具体是谁说的记不得了,大意是:“高级语言和低级语言的区别是,需要不需要写很多与程序的逻辑无关的东西。” 很多 if-else
,很难看出这个只是判断,还是程序逻辑/业务的判断。如果用 try-catch
,那么 try
代码块里面可以只写程序的逻辑,在 except
里面处理所有的异常。

即使在有异常处理机制的语言中,比如 Python,很多人喜欢做的一个事情是在子函数用 if 判断,然后 logger.error + return。其实不如 raise ,然后在调用者那里 try-catch,更能表达逻辑。

if not monitor_config.link:
    logger.error(f'{self} does not associate with link')
    return

此外,Python 语言内置的协议也大量使用了异常的机制。比如《fluent python》(314页)关于重载加运算符 __add__
就提到,为了遵守鸭子精神,不要测试 other 操作数的类型,而是应该捕获异常,然后抛出 NotImplemented

这样的好处是,比如我们定义了一个新的数据类型,支持和 int
相加  a.__add__(4)
。但是内置的 int
可不支持和我们自定义的类型相加, 4.__add__(a)
就会抛出异常。这时解释器尝试用  __radd__
来处理(即 a.__add__(4)
)。如果 int
__add__
是实现是相加对象的类型,如果不符合预期就抛出一个 TypeError
,就没有这样的便利了。

但是 EAFP 在某些情况下可能是不可行的,它的一个问题就是等错误发生的时候,程序已经运行了一半,如果函数会造成一些副作用,那么这个时候副作用已经发生了。这种情况下,如果没有数据事务这种外部的东西来提供原子性的话,就比较麻烦了,需要手动清理副作用的状态。而 LBFY 这种风格可以尽量保证提供给程序的参数正确,可以顺利运行完成。

其实我想讨论这二者的区别的真正地方是,在生活中也会有这两种风格的处理方式。

团队管理上 try-catch 更自由,更人性化,大家可以关注自己“做事的逻辑”而没有很多条条框框,在程序上 if 可能就多了一次判断,但是在实际生活中的话,这种 if 可能是各种各样的沟通和 ask permission,效率可就不只低这么多了。但是换句话来说,严谨的系统容不得做到半路才出现 “Exception”,还是需要“Look before you leap”的。

参考资料:

  1. https://www.codeproject.com/Tips/490765/If-else-instead-of-try-catch

  2. https://www.quora.com/When-should-I-use-try-catch-instead-of-if-else

  3. https://en.wikiquote.org/wiki/Grace_Hopper

  4. https://stackoverflow.com/questions/12265451/ask-forgiveness-not-permission-explain

  5. https://stackoverflow.com/questions/11360858/what-is-the-eafp-principle-in-python

原文 

https://www.kawabangga.com/posts/3022

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » LBYL与EAFP漫谈

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址