Je me retrouve souvent à renvoyer un booléen à partir d'une méthode, qui est utilisée à plusieurs endroits, afin de contenir toute la logique autour de cette méthode en un seul endroit. Tout ce que la méthode d'appel (interne) doit savoir, c'est si l'opération a réussi ou non.
J'utilise Python mais la question n'est pas nécessairement spécifique à ce langage. Il n'y a que deux options auxquelles je peux penser
- Lève une exception, bien que les circonstances ne soient pas exceptionnelles, et souviens-toi d'attraper cette exception à chaque endroit où la fonction est appelée
- Retourne un booléen comme je le fais.
Ceci est un exemple vraiment simple qui montre de quoi je parle.
import os
class DoSomething(object):
def remove_file(self, filename):
try:
os.remove(filename)
except OSError:
return False
return True
def process_file(self, filename):
do_something()
if remove_file(filename):
do_something_else()
Bien qu'il soit fonctionnel, je n'aime vraiment pas cette façon de faire quelque chose, il "sent" et peut parfois donner lieu à de nombreux if imbriqués. Mais, je ne peux pas penser à un moyen plus simple.
Je pourrais me tourner vers une philosophie et une utilisation plus LBYL os.path.exists(filename)
avant d'essayer de supprimer, mais il n'y a aucune garantie que le fichier n'aura pas été verrouillé entre-temps (c'est peu probable mais possible) et je dois encore déterminer si la suppression a réussi ou non.
Est-ce une conception "acceptable" et sinon, quelle serait une meilleure façon de concevoir cela?
Votre intuition à ce sujet est correcte, il existe une meilleure façon de le faire: les monades .
Que sont les monades?
Les monades sont (pour paraphraser Wikipedia) un moyen de chaîner des opérations ensemble tout en cachant le mécanisme de chaînage; dans votre cas, le mécanisme de chaînage est le
if
s imbriqué . Cachez cela et votre code sentira beaucoup plus agréable.Il y a quelques monades qui feront exactement cela ("Peut-être" et "Soit") et heureusement pour vous, elles font partie d' une bibliothèque de monades en python vraiment sympa!
Ce qu'ils peuvent faire pour votre code
Voici un exemple utilisant la monade "Soit" ("Disponible" dans la bibliothèque liée à), où une fonction peut retourner un succès ou un échec, selon ce qui s'est produit:
Maintenant, cela pourrait ne pas être très différent de ce que vous avez maintenant, mais considérez comment les choses se passeraient si vous aviez plus d'opérations pouvant entraîner un échec:
À chacun des
yield
s de laprocess_file
fonction, si l'appel de fonction renvoie un échec, laprocess_file
fonction quittera, à ce stade , en retournant la valeur d'échec de la fonction en échec, au lieu de continuer tout au long du reste et de retourner leSuccess("All ok.")
Maintenant, imaginez faire ce qui précède avec des
if
s imbriqués ! (Comment géreriez-vous la valeur de retour!?)Conclusion
Les monades sont sympa :)
Remarques:
Je ne suis pas un programmeur Python - j'ai utilisé la bibliothèque monade liée à ci-dessus dans un script que j'ai ninja pour une certaine automatisation de projet. Je suppose, cependant, qu'en général l'approche privilégiée et idiomatique consiste à utiliser des exceptions.
IIRC il y a une faute de frappe dans le script lib sur la page liée à bien que j'oublie où il est ATM. Je mettrai à jour si je me souviens.Je diff'd ma version contre la page de et trouvé:def failable_monad_examle():
->def failable_monad_example():
- l'p
enexample
était absent.Afin d'obtenir le résultat d'une fonction décorée disponible (comme
process_file
), vous devez capturer le résultat dans unvariable
et faire unvariable.value
pour l'obtenir.la source
Une fonction est un contrat, et son nom doit suggérer quel contrat elle remplira. À mon humble avis, si vous le nommez
remove_file
, il devrait supprimer le fichier et à défaut, cela devrait provoquer une exception. D'un autre côté, si vous le nommeztry_remove_file
, il devrait "essayer" de supprimer et de retourner booléen pour savoir si le fichier a été supprimé ou non.Cela mènerait à une autre question - devrait-il être
remove_file
outry_remove_file
? Cela dépend de votre site d'appel. En fait, vous pouvez avoir les deux méthodes et les utiliser dans des scénarios différents, mais je pense que la suppression du fichier en soi a de grandes chances de succès, je préfère donc n'avoir queremove_file
cette exception de rejet en cas d'échec.la source
Dans ce cas particulier, il peut être utile de réfléchir aux raisons pour lesquelles vous ne pourrez peut-être pas supprimer le fichier. Disons que le problème est que le fichier peut exister ou non. Ensuite, vous devez avoir une fonction
doesFileExist()
qui renvoie vrai ou faux, et une fonctionremoveFile()
qui supprime simplement le fichier.Dans votre code, vous devez d'abord vérifier si le fichier existe. Si c'est le cas, appelez
removeFile
. Sinon, faites d'autres choses.Dans ce cas, vous souhaiterez peut-être toujours
removeFile
lever une exception si le fichier ne peut pas être supprimé pour une autre raison, telle que des autorisations.Pour résumer, des exceptions devraient être levées pour des choses qui sont, bien, exceptionnelles. Donc, s'il est parfaitement normal que le fichier que vous essayez de supprimer n'existe pas, ce n'est pas une exception. Écrivez un prédicat booléen pour vérifier cela. D'un autre côté, si vous ne disposez pas des autorisations d'écriture pour le fichier, ou s'il se trouve sur un système de fichiers distant qui est soudainement inaccessible, ces conditions peuvent très bien être exceptionnelles.
la source