18 votes

Vérification des conditions et traitement des exceptions

Quand le traitement des exceptions est-il préférable à la vérification des conditions ? Il existe de nombreuses situations où je peux choisir d'utiliser l'un ou l'autre.

Par exemple, voici une fonction de sommation qui utilise une exception personnalisée :

# module mylibrary 
class WrongSummand(Exception):
    pass

def sum_(a, b):
    """ returns the sum of two summands of the same type """
    if type(a) != type(b):
        raise WrongSummand("given arguments are not of the same type")
    return a + b

# module application using mylibrary
from mylibrary import sum_, WrongSummand

try:
    print sum_("A", 5)
except WrongSummand:
    print "wrong arguments"

Et voici la même fonction, qui évite d'utiliser les exceptions

# module mylibrary
def sum_(a, b):
    """ returns the sum of two summands if they are both of the same type """
    if type(a) == type(b):
        return a + b

# module application using mylibrary
from mylibrary import sum_

c = sum_("A", 5)
if c is not None:
    print c
else:
    print "wrong arguments"

Je pense que l'utilisation de conditions est toujours plus lisible et plus facile à gérer. Ou ai-je tort ? Quels sont les cas appropriés pour définir des API qui lèvent des exceptions et pourquoi ?

1voto

Espen Points 5898

Vous devez lever une exception lorsque le paramètre contient une valeur inattendue.

Avec vos exemples, je recommanderais de lancer une exception lorsque les deux paramètres sont de types différents.

Lancer une exception est un moyen élégant d'interrompre un service sans encombrer votre code.

0voto

badp Points 5036

Peut-être sum_ est très bien seul. Et si, tu sais, on l'utilisait vraiment ?

#foo.py
def sum_(a, b):
    if type(a) == type(b):
        return a + b

#egg.py
from foo import sum_:
def egg(c = 5):
  return sum_(3, c)

#bar.py
from egg import egg
def bar():
  return len(egg("2"))
if __name__ == "__main__":
  print bar()

Si tu as couru bar.py vous obtiendriez :

Traceback (most recent call last):
  File "bar.py", line 6, in <module>
    print bar()
  File "bar.py", line 4, in bar
    return len(egg("2"))
TypeError: object of type 'NoneType' has no len()

Vous voyez, d'habitude on appelle une fonction avec l'intention d'agir sur sa sortie. Si vous vous contentez d'"avaler" l'exception et de renvoyer une valeur factice, les utilisateurs de votre code auront du mal à trouver une solution. Tout d'abord, le retour de trace est complètement inutile. Cette seule raison devrait suffire.

Celui qui veut corriger ce bogue doit d'abord revérifier bar.py puis analyser egg.py en essayant de comprendre d'où vient exactement le None. Après avoir lu egg.py ils devront lire sum_.py et nous espérons remarquer le retour implicite de None ; ce n'est qu'alors qu'ils comprennent le problème : ils ont échoué le contrôle de type à cause du paramètre egg.py pour eux.

Mettez un peu de complexité réelle là-dedans et les choses deviennent très vite moches.

Python, contrairement au C, est écrit avec le langage Il est plus facile de demander le pardon que la permission principe à l'esprit : si quelque chose ne va pas, je recevrai une exception. . Si vous me passez un None où je m'attends à une valeur réelle, les choses vont se briser, l'exception se produira loin de la ligne qui l'a causée et les gens se dans votre direction générale dans vingt langues différentes, puis modifiez le code pour qu'il lève une exception appropriée ( TypeError("incompatible operand type") ).

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