Manière correcte de la gestion des exceptions en Python?
J'ai cherché pour d'autres postes, comme je l'ai senti c'est plutôt un problème commun, mais tous les autres Python exception des questions que j'ai trouvé n'ont pas tenu compte de mon problème.
Je vais essayer d'être la plus précise ici que je peux, alors je vais donner un exemple direct. Et pleeeeease ne postez pas de solution de contournement pour ce problème spécifique. Je ne suis pas spécialement intéressé comment vous pouvez envoyer un e-mail beaucoup plus agréable avec xyz.
Je veux savoir comment vous traitent généralement des dépendants, des erreurs de déclarations.
Ma question est, comment gérer les exceptions bien, ceux qui dépendent l'un de l'autre, sens:
Seulement si la première étape a été un succès, essayez la prochaine, et ainsi de suite. Un plus le critère est: Toutes les exceptions doivent être prises, ce code doit être robuste.
Pour votre considération, par exemple:
try:
server = smtplib.SMTP(host) #can throw an exception
except smtplib.socket.gaierror:
#actually it can throw a lot more, this is just an example
pass
else: #only if no exception was thrown we may continue
try:
server.login(username, password)
except SMTPAuthenticationError:
pass # do some stuff here
finally:
#we can only run this when the first try...except was successful
#else this throws an exception itself!
server.quit()
else:
try:
# this is already the 3rd nested try...except
# for such a simple procedure! horrible
server.sendmail(addr, [to], msg.as_string())
return True
except Exception:
return False
finally:
server.quit()
return False
Ce qui semble extrêmement unpythonic pour moi, et le code de gestion d'erreur est le triple de la véritable code de commerce, mais d'un autre côté comment puis-je gérer plusieurs déclarations qui sont dépendants l'un de l'autre, la signification ci statement1 est indispensable pour statement2 et ainsi de suite?
Je suis également intéressé par les ressources appropriée de nettoyage, même Python peut gérer que pour lui-même.
Merci, Tom
- merci pour l'édition dbr, mais merci de ne pas modifier les choses que vous ne savez pas à propos de vous-même. J'ai édité le dos des critères critère, qui est en effet le singulier, comme un pluriel n'a pas de sens, où que vous l'avez édité.
- Opps, désolé à ce sujet (hm, ne pense pas que je ai jamais entendu parler au singulier de critères avant..)
Vous devez vous connecter pour publier un commentaire.
Au lieu d'utiliser le try/except de l'autre bloc, vous pouvez simplement retourner quand il erreurs:
C'est parfaitement lisible et Pythonic..
Une autre manière de faire, plutôt que de vous soucier de la mise en œuvre spécifique, décidez comment vous voulez que votre code, par exemple..
Puis écrire le code pour le
message()
méthode, la capture des erreurs que vous attendez, et d'élever votre propre personnalisé, et la poignée que lorsque c'est pertinent. Votre classe peut ressembler à quelque chose comme..import cElementTree
, puisElementTree
, enfin essayer delxml.et.ElementTree
par exemple)En général, vous souhaitez utiliser comme peu d'essayer de blocs que possible, en distinguant les conditions d'échec par les types d'exceptions qu'ils jettent. Par exemple, voici mon refactoring du code que vous avez posté le:
Ici, nous utilisons le fait que smtplib.SMTP(), à un serveur.login(), et le serveur.sendmail() tous lancer les différentes exceptions à aplatir l'arbre de blocs try-catch. Dans le bloc finally nous serveur de test explicitement pour éviter d'invoquer quit() sur le néant de l'objet.
On peut aussi utiliser trois séquentielle les blocs try-catch, retour Faux dans les conditions d'exception, s'il y a chevauchement exception des cas qui doivent être traités séparément:
Ce n'est pas tout à fait aussi agréable, que vous devez tuer le serveur en plus d'un endroit, mais maintenant, nous pouvons gérer exception spécifique types de différentes manières dans différents endroits sans maintien supplémentaire de l'état.
Si c'était moi, je serais probablement faire quelque chose comme ce qui suit:
Toutes les erreurs sont capturés et de débogage, la valeur de retour == True en cas de succès, et la connexion au serveur est correctement nettoyé si la connexion initiale est faite.
Juste en utilisant un essayez-bloc est le chemin à parcourir. C'est exactement ce qu'ils
sont conçus pour: seulement exécuter l'instruction suivante si la précédente
la déclaration n'a pas lever une exception. Comme pour la ressource propre-ups,
peut-être que vous pouvez vérifier la ressource si elle a besoin d'être nettoyé
(par exemple, myfile.is_open(), ...) Ce n'est d'ajouter quelques conditions supplémentaires, mais
ils seront exécutées uniquement dans les cas exceptionnels. Pour gérer le cas
que la même Exception peut être soulevée pour des raisons différentes, vous
devraient être capables de trouver la raison de l'Exception.
Je suggère de code comme ceci:
Il n'est pas rare, que le code de gestion d'erreur dépasse code de commerce. Corriger l'erreur de manipulation peut être complexe.
Mais pour augmenter l'entretien, il permet de bien séparer le code métier du code de gestion d'erreur.
Je voudrais essayer quelque chose comme ceci:
Toutes les méthodes (y compris
send_message
, vraiment) suivre le même protocole: ils retournent True si ils ont réussi, à moins qu'il n'en fait poignée une exception, ils n'ont pas l'emprisonner. Ce protocole permet également de gérer le cas où une méthode doit indiquer qu'il n'a pas sans soulever une exception. (Si la seule façon de vos méthodes échouent est de lever une exception, qui simplifie le protocole. Si vous êtes d'avoir à traiter avec beaucoup de non-exception de l'échec des états à l'extérieur de la méthode qui a échoué, vous avez probablement un problème de conception que vous n'avez pas travaillé encore.)L'inconvénient de cette approche est que toutes les méthodes doivent utiliser les mêmes arguments. J'ai opté pour aucun, avec l'espoir que les méthodes que j'ai écrasé sera à la fin de manipuler les membres de la classe.
L'avantage de cette approche est considérable, bien. Tout d'abord, vous pouvez ajouter des dizaines de méthodes pour le processus sans
send_message
obtenir plus complexe.Vous pouvez également devenir fou et de faire quelque chose comme ceci:
...mais à ce point, je pourrais me dire, "auto, vous travaillez le modèle de Commande assez difficile sans la création d'une classe de Commande. Peut-être que maintenant est le temps."
Pourquoi pas un gros essayer: bloc? De cette façon, si une exception est interceptée, vous aurez à aller tout le chemin à l'exception. Et tant que toutes les exceptions pour les différentes étapes sont différentes, vous pouvez toujours dire qui il était qui a déclenché l'exception.
J'aime bien David de répondre, mais si vous êtes coincé sur le serveur exceptions vous pouvez également vérifier pour le serveur si ce n'est ou des etats. J'ai aplati la méthode un peu peu qu'il est toujours un mais unpythonic à la recherche, mais plus lisible dans la logique au fond.