Coût des gestionnaires d'exceptions en Python

98

Dans une autre question , la réponse acceptée suggérait de remplacer une instruction if (très bon marché) en code Python par un bloc try / except pour améliorer les performances.

Mis à part les problèmes de style de codage, et en supposant que l'exception n'est jamais déclenchée, quelle différence cela fait-il (en termes de performances) d'avoir un gestionnaire d'exceptions, par rapport à ne pas en avoir, par rapport à une instruction if de comparaison à zéro?

Thilo
la source
6
Lorsque vous l'avez mesuré, qu'avez-vous appris?
S.Lott
1
Question connexe: stackoverflow.com/questions/1835756
tzot
Utilisez try / sauf si les chances de contrôle à l'exception d'une partie sont moindres et if / else si les chances sont plus grandes.
shadow0359

Réponses:

114

Pourquoi ne le mesurez-vous pas à l'aide du timeitmodule ? De cette façon, vous pouvez voir si cela est pertinent pour votre application.

OK, donc je viens d'essayer ce qui suit:

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))

Résultat:

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

Donc, comme prévu, ne pas avoir de gestionnaire d'exceptions est légèrement plus rapide (mais vous explose au visage lorsque l'exception se produit), et try/exceptest plus rapide qu'un explicite iftant que la condition n'est pas remplie.

Mais tout est dans le même ordre de grandeur et peu susceptible d'avoir une importance dans les deux cas. Ce n'est que si la condition est réellement remplie que la ifversion est nettement plus rapide.

Tim Pietzcker
la source
3
Intéressant. Donc try/exceptc'est plus rapide queif a != 0
Thilo
10
Ahh, un beau choix de mots: "tout est dans le même ordre de grandeur" ... Je soupçonne que beaucoup de gens qui évitent les exceptions le font en s'attendant à ce qu'ils soient 10 fois plus lents.
Garrett Bluma
Lancer votre code sur mon Fedora avec python 2.7.5 montre que la version "if" (0.08 usec / pass) est plus rapide que celle "try / except" (0.11 usec / pass) quand a = 1.
duleshi
@duleshi Intéressant. Je me demande si c'est une chose x86 / x64? Ou peut-être différentes extensions de processeur?
base
59

Cette question est en fait répondue dans la FAQ Conception et histoire :

Un bloc try / except est extrêmement efficace si aucune exception n'est déclenchée. En fait, attraper une exception coûte cher.

Michael
la source
3
Je me demandais simplement à quel point «extrêmement efficace» est efficace. Apparemment, c'est plus rapide que même une simple déclaration «si».
Thilo
L'extrait que vous avez publié provient de la FAQ sur la conception et l'histoire .
nitsas
Peut-être que «extrêmement efficace» signifie quelque chose comme ce qui se fait en Java ?
ebk
19

Cette question est trompeuse. Si vous supposez que l'exception n'est jamais déclenchée, aucun des deux n'est le code optimal.

Si vous supposez que l'exception est déclenchée dans le cadre d'une condition d'erreur, vous êtes déjà en dehors du domaine de la volonté de code optimal (et vous ne le gérez probablement pas à un niveau fin comme celui-là de toute façon).

Si vous utilisez l'exception dans le cadre du flux de contrôle standard - qui est la méthode pythonique "demander pardon, pas permission" - alors l'exception va être déclenchée, et le coût dépend du type d'exception, du type de si et quel pourcentage de temps vous estimez que l'exception se produit.


la source