web-dev-qa-db-fra.com

Python: Est-ce une mauvaise forme de lever des exceptions dans __init__?

Est-il considéré comme une mauvaise forme de lever des exceptions dans __init__? Dans l'affirmative, quelle est la méthode acceptée pour générer une erreur lorsque certaines variables de classe sont initialisées comme None ou d'un type incorrect?

111
meppum

Déclencher des exceptions dans __init__() est tout à fait correct. Il n'existe aucun autre bon moyen d'indiquer une condition d'erreur dans un constructeur, et il existe plusieurs centaines d'exemples dans la bibliothèque standard où la construction d'un objet peut déclencher une exception.

La classe d'erreur à soulever, bien sûr, dépend de vous. ValueError est préférable si le constructeur a reçu un paramètre non valide.

142
John Millikin

Il est vrai que la seule manière appropriée d'indiquer une erreur dans un constructeur est de lever une exception. C'est pourquoi en C++ et dans d'autres langages orientés objet conçus avec une sécurité d'exception à l'esprit, le destructeur n'est pas appelé si une exception est levée dans le constructeur d'un objet (ce qui signifie que l'initialisation de l'objet est incomplète). Ce n'est souvent pas le cas dans les langages de script, comme Python. Par exemple, le code suivant lève une erreur AttributeError si socket.connect () échoue:

class NetworkInterface:
    def __init__(self, address)
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.connect(address)
        self.stream = self.socket.makefile()

    def __del__(self)
        self.stream.close()
        self.socket.close()

La raison en est que le destructeur de l'objet incomplet est appelé après l'échec de la tentative de connexion, avant l'initialisation de l'attribut de flux. Vous ne devez pas éviter de lever des exceptions de la part des constructeurs, je dis simplement qu'il est difficile d'écrire entièrement du code sécurisé d'exception en Python. Certains développeurs de Python évitent complètement d'utiliser des destructeurs, mais c'est une question d'un autre débat.

23
Seppo Enarvi

Je ne vois aucune raison pour que ce soit une mauvaise forme.

Au contraire, l'une des choses que les exceptions sont connues pour bien fonctionner, par opposition au renvoi de codes d'erreur, est que les codes d'erreur sont généralement ne peuvent pas être retournés par les constructeurs. Donc, au moins dans des langages comme C++, lever des exceptions est le seul moyen de signaler des erreurs.

11
Edan Maor

La bibliothèque standard dit:

>>> f = file("notexisting.txt")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: 'notexisting.txt'

De plus, je ne vois pas vraiment pourquoi cela devrait être considéré comme une mauvaise forme.

5
sth

Je pense que c'est le cas parfait pour l'exception ValueError intégrée.

3
Teddy

Il est inévitable de générer des erreurs depuis init dans certains cas, mais faire trop de travail dans init est un mauvais style. Vous devriez envisager de créer une usine ou une pseudo-usine - une méthode de classe simple qui renvoie un objet réglé.

2
Ctrl-C

Je suis d'accord avec tout ce qui précède.

Il n'y a vraiment pas d'autre moyen de signaler que quelque chose s'est mal passé dans l'initialisation d'un objet que de lever une exception.

Dans la plupart des programmes, les classes où l'état d'une classe dépend entièrement des entrées de cette classe, nous pouvons nous attendre à ce qu'une sorte de ValueError ou TypeError soit déclenchée.

Les classes avec des effets secondaires (par exemple, qui font du réseautage ou des graphiques) peuvent générer une erreur dans init si (par exemple) le périphérique réseau n'est pas disponible ou si l'objet canevas ne peut pas être écrit. Cela me semble raisonnable, car vous voulez souvent connaître les conditions de défaillance le plus tôt possible.

2
Salim Fadhley