Python的异常处理效率比PHP或其他语言更高吗?
我一直被告知(至少在PHP中),使用try... catch
块来控制程序流程是非常不好的做法。我学到的经验是,这种结构应该只用来处理意外错误,而不是用来决定程序的逻辑流程,因为catch
块的开销比较大。
现在我在学习Python,发现到处都有异常处理的用法,还有一个叫做EAFP的原则。这是否意味着Python在处理异常方面更高效,所以我不需要太担心它们对程序流程的影响?还是说这个原则在Python中依然适用?如果不是,那PHP是例外,还是Python才是例外呢?
6 个回答
伟大的亚历克斯·马特利在《Python In A Nutshell》这本书中很好地介绍了EAFP和LBYL这两种编程风格。(他更倾向于使用EAFP)
我认为EAFP(即“先尝试,后处理异常”)并不是鼓励我们用异常来控制程序的流程。它的意思是,我们在引用字典中的某个键或者对象的某个属性之前,不需要特意去检查它是否存在。
把抛出异常当作替代if
语句,或者用来替代正确的while
语句,甚至在循环中替代break
或continue
的做法,并不符合这个原则。这种做法是懒惰且容易出错的编程方式,应该尽量避免。
历史上,在像C++这样的语言中,异常处理的速度比其他控制流程的方式要慢得多,尤其是在同一种语言内部。
在C++中,有两个原因导致这种情况:
- 抛出异常的过程非常复杂。需要“展开”调用栈,而在原生代码中做到这一点比在高级虚拟机语言中要困难得多。
- 正常的直接控制流程非常快。因为它是原生代码,分支只需要几条指令,而异常需要回滚调用栈,这涉及到一个复杂的算法(比如查找一个可能很大的、压缩过的表中的栈数据等等)。
这种性能差异导致了关于异常处理的一般看法:只在不寻常的情况下使用它,这样就能在最有利的地方使用,而不是在会影响性能的地方。
但这种看法并不适用于高级语言,这里有两个原因:
- 回滚调用栈的过程简单得多。调用栈很容易检查;你不需要神秘的表格来知道应该回滚多少,以及在任何时刻构造了哪些对象。
- 正常的程序流程本身就比较慢。在基于虚拟机的语言中,所有操作本身就需要更多的工作。
虽然异常处理仍然不是免费的,但这种性能差异已经不再是需要担心的问题。这意味着在C++中形成的一般看法在这里是不适用的。在正常的程序流程中,异常处理是经常使用的。
实际上,异常处理已经内置在语言中,成为你经常使用的结构。每次你使用迭代器时,比如每个 for x in xrange(1000)
,都会使用 StopIteration
异常来结束循环。
在Python中,选择使用异常处理还是线性控制流程,应该根据哪种方式更合理来决定。不要仅仅根据性能来选择,除非你确实在一个性能重要的内循环中;在这种情况下,像往常一样,进行性能分析,看看是否真的重要。
(我不能代表PHP说什么。)