实用 Python:EAFP VS. LBYL
Python 中的一个惯用手法,也是常常为那些使用异常被当成,好吧,异常的编程语言的人们所惊讶的是, EAFP : "比之请求许可,请求原谅更容易些"。简单说一下,EAFP 意味着你应该只做那些期望做的事,并且当异常从操作中抛出来的时候捕获它们,然后处理之。而人们通常使用的是 LBYL : "三思而后行"。相比 EAFP,LBYL 是你搜下检查某些事情是否会成功,然后仅当你知道它能工作的时候才继续。
如果这一切在散文层面没有任何意义,那么别担心,代码将使其显而易见。让我们考虑一个例子,接收一个可能(或者可能不会)具有某个特定键的字典。在 LBYL 中,你将在第一次使用这个键之前检查它:
if "key" in dict_:
value += dict_["key"]
这阻止了抛出一个 KeyError
异常的可能,这似乎是符合逻辑的。但是这个代码给用户的感觉是,异常情况时该字典拥有这个键,而不是该键可能不存在,这可能不是真的。没有注释说明一般情况,那么如果你不是这个代码的作者,那么你可能就不知道什么才是期望为真的。或者换句话说,这个代码似乎强调该键在该字典中确实有些特殊,而未必真的会出现这种情况或者有那么重要。
但如果该键一般会存在于该字典中,或者不应该被认为是任何形式的异常呢?EAFP 让你以一种不一样的方式编写同样的代码,它淡化了该键存在于该字典中的重要性:
try:
value += dict_["key"]
except KeyError:
pass
阅读这段代码,它告诉了你什么?似乎表明,该键通常会存在于该字典中,但有时候不是。如果该键缺失,那么这也不是什么大事,但如果它确实存在,那么应该用它来调用一个函数。这种将代码意味着什么清晰的传达给开发者对 Python 来说是非常重要的,因此它优于 LBYL 风格,后者可能错误的传达了该键的存在多么常见/罕见/重要。
有些人读到这里,会说相比之 LBYL,EAFP 版本更长更明显,这显然是正确的。但“显式优于隐式”这种思想是关键的 Python 自身的设计方针 ,因此,该代码的明确性是有意为之的。
除了潜在的明确性/冗长性,人们往往对 EAFP 的另一个担忧是性能。如果你是从一种触发异常是非常昂贵的编程语言来到 Python 的,那么这种担忧是可以理解的。但由于异常像 EAFP 这样用于控制流程,Python 实现努力使异常开销变小,因此编写代码时,你不应该担心异常的成本。
虽然,使用 EAFP 要提醒一下,适用于任何处理捕获异常的代码的是,不要在你的 try
中的代码之上放置过于宽泛的代码。例如,可能像这样开始写代码是很有诱惑力的:
try:
do_something(dict_["key"])
except KeyError:
pass
该代码的问题是,如果 do_something() 自身抛出了一个你不想抑制的 KeyError
,会发生什么呢?在这种情况下,你应该更明确了解你正考虑的特殊情况是什么:
try:
value = dict_["key"]
except KeyError:
pass
else:
do_something(value)
使用任何你有可能抑制异常的代码块,你想要尽可能多的本地化在 try
块中执行的代码。现在,如果在像 EAFP 似乎过于明确的这种情况中,你更倾向于 LBYL,那么使用 LBYL 也没有什么错误。
if "key" in dict_:
do_something(dict["key"])
你在本文中应该获得的关键是,EAFP 在 Python 中是一种合法的编码风格,并且当其有意义时,你应该随意使用它。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论