return – Sam & Max http://sametmax.com Du code, du cul Wed, 30 Oct 2019 15:34:04 +0000 en-US hourly 1 https://wordpress.org/?v=4.9.7 32490438 Quelle valeur retourner quand on ne trouve rien en Python ? http://sametmax.com/quelle-valeur-retourner-quand-on-ne-trouve-rien/ http://sametmax.com/quelle-valeur-retourner-quand-on-ne-trouve-rien/#comments Wed, 30 Jan 2013 09:25:16 +0000 http://sametmax.com/?p=4321 None. Ne rien retourner, c'est donc choisir de retourner None. Or la valeur de retour est une choix d'API, et va dicter comme les gens vont utiliser votre fonction. Il convient donc de bien choisir sa valeur de retour "à vide".]]> 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 "", line 1, in 
    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 "", line 1, in 
    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
]]>
http://sametmax.com/quelle-valeur-retourner-quand-on-ne-trouve-rien/feed/ 5 4321