web-dev-qa-db-ja.com

Pythonの例外ハンドラーのコスト

別の質問 で、受け入れられた回答は、パフォーマンスを改善するために、Pythonコードでtry/exceptブロックで(非常に安い)ifステートメントを置き換えることを提案しました。

コーディングスタイルの問題は別として、例外がトリガーされないと仮定すると、例外ハンドラーを持つことと、持たないこと、ゼロと比較するifステートメントを持つこととのパフォーマンスの違いはどれくらいありますか?

75
Thilo

timeitモジュール を使用して測定しないのはなぜですか?これにより、アプリケーションに関連するかどうかを確認できます。

OK、だから私は次のことを試しました:

_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バージョンが大幅に高速になります。

92
Tim Pietzcker

この質問は、実際には Design and History FAQ で回答されています:

Try/exceptブロックは、例外が発生しない場合に非常に効率的です。実際に例外をキャッチするのは高価です。

47
Michael

この質問は誤解を招くものです。例外がneverトリガーであると仮定した場合、どちらも最適なコードではありません。

エラー条件の一部として例外がトリガーされると仮定した場合、最適なコードを必要とする領域の外に既にあります(おそらく、そのようなきめ細かいレベルでそれを処理していないでしょう)。

Pythonの「許可ではなく、許しを求める」方法である標準制御フローの一部として例外を使用している場合、例外がトリガーされ、コストは例外の種類、ifの種類に依存します、例外が発生すると推定する時間の割合。

15
user79758