Python 中异常处理程序的开销

另一个问题中,为了提高性能,公认的答案建议在 Python 代码中替换(非常便宜的) if 语句,使用 try/腰包块。

抛开编码风格问题不谈,假设异常永远不会触发,那么拥有异常处理程序与没有异常处理程序、比较为零的 if 语句(从性能方面而言)有多大区别呢?

59526 次浏览

为什么不使用 timeit模块来度量它呢? 这样你就可以看到它是否与你的应用程序相关。

好的,我刚刚试了下面的方法:

import timeit


statements=["""\
try:
b = 10/a
except ZeroDivisionError:
pass""",
"""\
if a:
b = 10/a""",
"b = 10/a"]


for a in (1,0):
for s in statements:
t = timeit.Timer(stmt=s, setup='a={}'.format(a))
print("a = {}\n{}".format(a,s))
print("%.2f usec/pass\n" % (1000000 * t.timeit(number=100000)/100000))

结果:

a = 1
try:
b = 10/a
except ZeroDivisionError:
pass
0.25 usec/pass


a = 1
if a:
b = 10/a
0.29 usec/pass


a = 1
b = 10/a
0.22 usec/pass


a = 0
try:
b = 10/a
except ZeroDivisionError:
pass
0.57 usec/pass


a = 0
if a:
b = 10/a
0.04 usec/pass


a = 0
b = 10/a
ZeroDivisionError: int division or modulo by zero

因此,正如预期的那样,没有任何异常处理程序会稍微快一点(但是当异常发生时会在您面前爆炸) ,而且只要不满足条件,try/except就比显式 if快。

但这些都在同一个数量级内,不管怎样都不太重要。只有在实际满足条件的情况下,if版本的速度才会快得多。

这个问题实际上在 设计与历史常见问题中得到了回答:

如果没有引发异常,try/夹非常有效。 实际上,捕获异常是很昂贵的。

这个问题是有误导性的。如果假设异常是 永远不会触发的,那么两者都不是最佳代码。

如果假设异常是作为错误条件的一部分触发的,那么您已经超出了需要最优代码的范围(而且您可能无论如何都不会在细粒度级别处理它)。

如果你使用异常作为标准控制流程的一部分-这是 Python 的“请求原谅,而不是许可”的方式-那么异常就会被触发,成本取决于异常的类型,如果的类型,以及你估计异常发生的百分比。

在 Python 3.11中,

“Zero-cost” exceptions are implemented. The cost of try statements is almost eliminated when no exception is raised. (Contributed by Mark Shannon in bpo-40222.)

Https://docs.python.org/3.11/whatsnew/3.11.html#optimizations

问: 在 python 中 try/catch是否昂贵?

当我使用 try catch 时,我应该担心吗? 以什么方式?

这只是对已经给出的答案的总结。

答: 当有异常时,if会快得多,否则就没有了。

@ SuperNova 写道,异常是零成本的,所以它比使用 if 语句 无一例外更快。然而,处理例外情况的成本很高,因此:

尝试那些可能失败的事情。如果可能的话,避免尝试那些你知道会失败的事情

例如:
  1. 好的情况下,使用尝试:
try:
x = getdata() # an external function
except:
print('failed. Retrying')
  1. 错误的情况,这里 if-version 是首选:
y = f(x) # f never fails but often returns 0
try:
z = 1 / y # this fails often
except:
print('failed.')


# if-version
y = f(x)
if y != 0:
z = 1 / y
else:
print('failed.')