python书写风格出现了什么体_Python Tips - 防御性编程风格 EAFP vs LBYL

关键词EAFP LBYL

即使你已经使用Python编程了很久,你可能也会对这两个词感到陌生。它们是什么?什么时候会出现?该怎么选择?思考以上问题来阅读本文。

What?

可以将它们理解成两种编程风格,为了增强程序的健壮性,通常会增加一些检查数据项的代码,用术语来说就是防御性编程,在检查的时候通常有一下两种风格。

“Easier to Ask for Forgiveness than Permission.”(请求宽恕比许可更容易)— EAFP

“Look Before You Leap”(三思而后行 )— LBYL

Where?

如果看了上面的解释,你可能还没懂他们是怎么体现在编程中,那来看一下具体的应用场景。

例1:当你需要从字典中取出key所对应的value并进行操作时

EAFP

try:

x = test_dict["key"]

except KeyError:

# key 不存在

LBYL

if "key" in test_dict:

x = test_dict["key"]

else:

# key 不存在

例2:当你需要创建一个目录或文件的时候

EAFP

try:

os.makedirs(path)

except OSError as exception:

if exception.errno != errno.EEXIST:

# PermissionError 等异常

raise

else:

# path 目录已存在

LBYL

if not os.path.exists(path):

os.makedirs(path)

else:

# path 目录已存在

还有很多相似的场景例子,以上可以再次总结一下EAFP和LBYL的区别EAFP(操作前不检查,出了问题由异常处理来处理)代码表现:try...except...

LBYL(操作前先检查,再执行)代码表现:if...else...

Which?

这两种相对应的编程风格各有好坏,那么该如何选择?何时用何种风格来编写健壮的代码呢?

代码效率

从时间效率上进行选择,通常有一下四种情况:LBYL检查成功时的时间

LBYL检查失败时的时间

EAFP没有抛出异常时的时间

EAFP抛出异常时的时间EAFP 的异常处理往往也会影响一点性能,因为在发生异常的时候,程序会进行保留现场、回溯traceback等操作,但在异常发生频率比较低的情况下,性能相差的并不是很大。

而 LBYL 则会消耗更高的固定成本,因为无论成败与否,总是执行额外的检查。

相比之下,如果不引发异常,EAFP 更优一些,

代码易读性当性能速度不用作考虑条件时,来看看代码的易读性。. EAFP将业务逻辑代码,跟防御性代码隔离开,让开发者可以更专注于开发业务逻辑,不管数据变量是否合理,按照正常的逻辑思维执行下去,如果发生错误就在异常里面纠正。

LBYL则容易打乱开发者的思维,在做一件事之前,总是要先要判断能不能这样做,传入的数据是否合理,类型是否正确,需要增加很多判断内容,代码连贯性差,常见的一堆if判断,多数就是这种风格导致。

代码风险

在一个多线程的环境中,LBYL 面临着一个风险,即条件判断与紧接着的代码执行的竞争。如果代码涉及到原子操作,强烈推荐使用 EAFP 风格,比如某段程序的逻辑是对文件/数据库操作,使用 LBYL 风格:

if exists(file):

do_something()

# or

if has(key):

do_something()

就变成了2步操作,在多线程并发的时候,可能文件的状态或者key 的状态已经被其它现成改变了,而 EAFP 风格则可以确保原子性。

try

read_file(file)

except :

pass

两种风格存在的必要通过上面的对比,会感觉 EAFP要比 LBYL 哪方便都好一些。既然是这样,为什么还要讨论对比呢?

之前在编写 Java/C/C++的时候通常都是采用 LBYL风格,很少在一些不可控的情况才会使用 EAFP 风格。Python 的动态类型(duck typing)决定了 EAFP,而 Java等强类型(strong typing)决定了 LBYL。语言之间的设计哲学差异,Java 对类型要求非常严格,要求明确,类/方法等,它假定你应该知道,任何时候你正在使用的对象类型,以及它能做什么。相反,Python 的鸭子类型意味着你不必明确的知道对象的显示类型是什么,你只需要关心你在使用时候它能有相应的反馈。在这种宽松的限制下,唯一明确的态度就是认为代码会工作,准备面对结果。

这无关语言的好坏,每一门语言都有自己的哲学与态度,正确的对待,理解。

结论

如果有潜在不可控的问题,使用 EAFP

如果预先检查成本很高,请使用 EAFP

如果您希望操作在大多数时间成功,请使用 EAFP

如果您预计操作失败的时间超过一半,请使用 LBYL

如果速度不重要,使用您认为更易读的风格

End之前在给一些朋友做培训的时候,看过一些初学者的代码,代码里面好多 try…except ,问他们为什么要这么写,他们也不懂,只是看了别人的例子有这么写,报了错就 try,代码顺利执行了,就觉得没问题了。我还同他们讲为什么这样写,还安利他们在了解可能发生的情况下尽量使用 if 判断,要把错误的情况了如指掌,才能更好地编写健壮的代码。但是现在想想 try 也不失为一种好的方式,爬虫存在的风险,就是易变,网站变了,接口变了, 加密变了,爬虫就要做相应的改变,try到了突变的异常,不影响全局。

抛开爬虫来说,业务上的代码,我还是更倾向于使用 LBYL 风格,业务上的异常必须要有掌控全局的健壮性,针对不同情况,都要了解到,思考到,并解决掉。

具体那种风格更适合,相信你看完本文,也有了自己的一些思考,编写易读的代码,健壮的程序。

(仅对 Python 的一些特性来讲,我更倾向于 EAFP 风格的代码。对于编程的严谨性来讲,我更喜欢 LBYL,谁让我是 Java 转到 Python 的处女座呢。)

更多姿势来关注我的公众号:一口袋码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值