122

另一个问题中,接受的答案建议用 try/except 块替换 Python 代码中的(非常便宜的)if 语句以提高性能。

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

4

5 回答 5

133

你为什么不使用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版本才会明显更快。

于 2010-03-26T08:54:50.650 回答
75

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

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

于 2010-03-27T14:56:19.770 回答
20

这个问题具有误导性。如果您假设从未触发异常,则两者都不是最佳代码。

如果您假设异常是作为错误条件的一部分触发的,那么您已经超出了想要优化代码的范围(而且您可能并没有像那样在细粒度级别上处理它)。

如果您将异常用作标准控制流的一部分——这是 Python 式的“请求宽恕,而不是许可”方式——那么将触发异常,并且成本取决于异常的类型,if 的类型,以及您估计异常发生的时间百分比。

于 2010-09-18T21:12:39.553 回答
8

在 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

于 2021-07-16T12:09:49.163 回答
2
问:try/catchpython 成本高吗?

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

这只是已经给出的答案的摘要。

A:出现异常时if要快得多。否则没有。

@SuperNova 写道,异常的成本为零,因此它比没有异常时使用 if 语句要快。但是,处理异常的成本很高,因此:

对可能失败的事情使用 try。如果可能,避免尝试你知道会失败的事情

例子:
  1. 好案例,使用 try:
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.')

于 2021-09-17T08:06:01.673 回答