Hier je me suis dit que maintenant je mettrai de la musique à écouter pendant le tuto. Parce que. Donc détendez-vous avez un petit morceau de K’s Choice :
Techniquement une fonction Python ne peut pas ne rien retourner. Il n’existe rien de telle qu’un procédure dans ce langage. Si vous ne donnez aucune valeur de retour, elle va retourner None
.
>>> def metal(): ... 1 + 1 ... >>> print metal() None |
Ne rien retourner, c’est donc choisir de retourner None
. Or la valeur de retour est un choix d’API, et va dicter comme les gens vont utiliser votre fonction. Il convient donc de bien choisir sa valeur de retour “à vide”.
Fonction qui produit un résultat
La fonction qui produit un résultat, par exemple on lui donne deux valeur, et elle calcule une troisième, est le cas le plus facile.
Si la valeur peut être calculée, on retourne la valeur. Sinon, c’est qu’il y a un problème avec les arguments. Comme Python n’est pas un langage compilé, on ne check pas la nature des arguments. De plus parfois ce n’est pas tant un problème de nature que de valeur (comme le domaine de définition en maths). Dans ce cas, le mieux est de lever une exception (souvent ValueError ou un descendant) :
def by_poison(arg1, arg2): # faire l'opération ici # ah, ça marche pas ? raise ValueError("{} et {} doivent être bidule truc sinon ça ne marche pas".format(arg1, arg2)) |
On évite la plupart du temps les valeurs qui veulent dire sémantiquement “mauvaise opération” comme NaN
en Python. On préférera lever une exception. None
est rarement une bonne idée ici.
Fonction qui cherche un résultat
Ce genre de fonction ne va pas lever une exception sous prétexte qu’elle n’a pas trouvé un truc. Ne pas trouver est un état tout à fait normal (à moins que la présence soit requise, mais dans ce cas lever l’exception ne doit pas être à ce niveau mais à celui plus haut de toute façon).
Si c’est une vérification de présence, on retourne juste True
/ False
:
def is_inside(value, other_value): # vérifier que value est dans other value return True # ou False |
Notez que si vous faites les choses proprement, il vaut mieux overrider __contains__
pour permettre d’utiliser in
directement.
Si votre recherche doit retourner une liste d’items (comme les lignes dans une base de données), dans ce cas quand on ne trouve rien, il vaut mieux retourner une liste vide. Cela permet de faire une boucle for
sur le résultat dans tous les cas sans vérification ni side effect.
def inignition(query): # chercher un truc, et si on trouve le retourner # et tout à la fin, au cas où return [] |
Si vous cherchez un élément en particulier (genre un nombre premier dans la liste donnée), le mieux est de retourner None
si il ne fait pas partie des données retournable. Si None
fait partie des données trouvable, on retourne au fait de lever des exceptions :(. Mais c’est qu’il y a un problème ailleurs, car None
ne devrait pas être une donnée significative.
def fed(truc, bidule): # chercher un truc, et si on trouve le retourner # et tout à la fin, au cas où return None |
Certains cas particuliers demandent de retourner le même type que celui recherché. Il n’y a pas de règle pour ça, il va falloir utiliser votre tête, pour faire quelque chose de cohérent.
Par exemple, rechercher la chaîne la plus longue dans une séquence doit-il retourner None
si aucune n’est trouvée, ou une chaîne vide ? Il n’y a pas de bonne réponse, c’est selon la sémantique de votre appli. Si elle traite uniquement avec des types string, une chaîne vide peut avoir du sens. Si c’est la présence ou l’absence de chaîne la plus longue qui est importante, alors None
sera plus approprié.
A l’inverse, des fonctions comme “trouver la position” ne doit pas retourner -1 comme dans la plupart des autres langages. -1 est en effet très significatif en Python (pour le slicing par exemple). Évitez donc d’utiliser le même type pour dire “rien n’est trouvé” si la valeur risque d’être significative. Dans ce cas choisissez None
.
megalist[:littlelist.search(truc)] # si littlelist.search(truc) retourn -1 c'est la merde ! |
La bibliothèque Python a tendance à lever des exception à tout va :
>>> s = 'Tasse' >>> s.index('p') Traceback (most recent call last): File "<ipython-input-14-e5567af6b163>", line 1, in <module> s.index('p') ValueError: substring not found |
C’est un comportement acceptable, mais ce n’est pas le plus pratique. Vous allez voir pourquoi.
Valeur par défaut
Retourner None
quand on ne trouve rien peut résulter en une API extrêmement agréable car l’action la plus utilisée comme contre mesure est d’avoir une valeur par défaut. Prenez pas exemple un dictionnaire. Récupérer un élement et assigner une valeur par défaut si il manque ressemble à ça avec une exception :
>>> dicos = {'petit larousse' : 'dans la tête', 'gros robert' : 'dans le derriere'} >>> dicos['urban dictionary'] # un entrée inexistante lève l'exception KeyError Traceback (most recent call last): File "<ipython-input-18-0d425e038e32>", line 1, in <module> dicos['urban dictionary'] KeyError: 'urban dictionary' >>> try: # du coup on doit faire un try ... ou_ca = dicos['urban dictionary'] ... except KeyError: ... ou_ca = 'sur le net' ... >>> ou_ca 'sur le net' |
Mais Python permet un raccourcis pour ça, vraiment sympas :
>>> dicos.get('urban dictionary', 'sur le net') 'sur le net' |
La méthode get()
permet de récupérer une valeur, et si la clé n’existe pas, elle retourne le deuxième argument. Or, par défaut, le second argument est None :
>>> print dicos.get('urban dictionary') None |
Donc si vous avez une fonction qui cherche quelque chose et qui risque de ne pas trouver, il peut être très pratique de proposer une argument comme valeur de retour par défaut, et de le mettre à None
:
def and_blind(cherche, default=None): if je_trouve_pas_cherche: return default |
Encore une fois un article simple, lisible et intéressant. Au final c’est que de la logique mais c’est vrai que rappeler les bases ne fait jamais de mal !
C’est également une très bonne idée de mettre un morceau de musique à écouter en lisant l’article. A renouveler dès que possible! :)
Par contre le Mario est bien mais la fenêtre est légèrement trop petite et quand on appuie sur haut c’est le page entière qui scroll… pas très pratique. (Testé sous Chrome)
En fait, quand tu ne trouves pas de sujet d’article tu devrais retourner None. Au lieu de quoi tu retournes un article qui parle de ce qu’on retourne quand on ne trouve rien en python.
Qu’est-ce qu’on doit faire? Ce que tu dis, ou ce que tu fais?
L’article n’est pas la valeur de retour, c’est la docstring. Débutant va.
Les vidéos youtube dans les docstrings, j’avais encore jamais fait ! ^^