139 votes

Coût des gestionnaires d'exception en Python

En autre question La réponse acceptée suggérait de remplacer une instruction if (très bon marché) dans le code Python par un bloc try/except afin d'améliorer les performances.

En dehors des questions 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'exception, ou de ne pas en avoir, ou d'avoir une déclaration if comparant à zéro ?

148voto

Tim Pietzcker Points 146308

Pourquoi ne pas la mesurer à l'aide du timeit module ? De cette façon, vous pouvez voir si c'est pertinent pour votre candidature.

OK, je viens d'essayer ce qui suit (en utilisant Python 3.11.1 sur Windows 11) :

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.06 usec/pass

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

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

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

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

a = 0
b = 10/a
Traceback (most recent call last):
  File "<stdin>", line 5, in <module>
  File "C:\Python311\Lib\timeit.py", line 178, in timeit
    timing = self.inner(it, self.timer)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<timeit-src>", line 6, in inner
ZeroDivisionError: division by zero

Comme vous pouvez le constater, il n'y a pas de grande différence entre l'utilisation d'un try/except par rapport à une clause explicite de if à moins que l'exception ne soit déclenchée. (Et bien sûr, ne pas avoir de structure de contrôle est plus rapide, même si ce n'est pas de beaucoup, et cela fera planter le programme si quelque chose se passe mal).

Comparez ces résultats à ceux obtenus en 2010 :

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

Il semble que le PC que j'utilise aujourd'hui soit environ deux fois plus rapide que celui que j'avais à l'époque. Le coût du traitement d'une exception semble identique et les opérations "normales" (arithmétique) ont été améliorées encore plus que le traitement des structures de contrôle, mais la remarque faite il y a toutes ces années reste valable :

Tout cela est du même ordre de grandeur et n'a que peu d'importance dans un sens ou dans l'autre. Ce n'est que si la condition est effectivement remplie (souvent), que la if est nettement plus rapide.

80voto

Michael Points 1943

La réponse à cette question se trouve dans le FAQ sur la conception et l'histoire :

Un bloc try/except est extrêmement efficace si aucune excepti Le fait d'attraper une exception est coûteux.

21voto

Trying2Learn Points 11

Dans 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

20voto

Cette question est trompeuse. Si l'on suppose que l'exception est jamais déclenché, ni l'un ni l'autre n'est un code optimal.

Si vous supposez que l'exception est déclenchée dans le cadre d'une condition d'erreur, vous n'êtes déjà plus dans le domaine du code optimal (et vous ne le traitez probablement pas à un niveau aussi fin).

Si vous utilisez l'exception dans le cadre du flux de contrôle standard - ce qui correspond à la méthode Python "demander le pardon, pas la permission" - alors l'exception sera déclenchée, et le coût dépend du type d'exception, du type de si, et du pourcentage de temps que vous estimez nécessaire pour que l'exception se produise.

6voto

Hunaphu Points 136
Q : Est-ce que try/catch coûteux en python ?

Dois-je m'inquiéter lorsque j'utilise try catch ? De quelle manière ?

Ceci n'est qu'un résumé des réponses déjà données.

R : En cas d'exception if est beaucoup plus rapide. Sinon, non.

@SuperNova écrit que les exceptions ont un coût nul et que c'est donc plus rapide que d'avoir une déclaration if. lorsqu'il n'y a pas d'exception . Cependant, la gestion des exceptions est coûteuse :

Utilisez l'expression "essayer" pour les choses qui peuvent échouer. Dans la mesure du possible, évitez d'utiliser try pour les choses dont vous savez qu'elles échoueront.

Exemple :
  1. Bon cas, essayez :

    try: x = getdata() # an external function except: print('failed. Retrying')

  2. Mauvais cas, ici if-version est préférable :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X