IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

DEBUGGING et valeur de retour de fonction - Comment faites-vous ?


Sujet :

Python

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2006
    Messages : 35
    Points : 21
    Points
    21
    Par défaut DEBUGGING et valeur de retour de fonction - Comment faites-vous ?
    Bonjour,

    Je voudrais ouvrir une discution sur la façon dont vous traiter les erreurs en retour d'une fonctions. Je ne parle pas d'erreurs avec sortie du programme mais juste des cas où votre fonction ne peut retourner un résultat du type attendu.

    Par exemple, vous avez une fonction qui cherche un mot dans un texte mais le mot n'y figure pas... Il faut alors que la fonction signale au programme ce cas particulier.
    Comment traitez-vous ce problème ?


    Le soucis classique avec une fonction, c'est lors du retour des résultats. La fonction retourne normalement une valeur mais il est possible qu'elle retourne aussi une valeur d'échec. Et cette valeur d'échec n'a pas forcément le même type que la valeur de retour.

    Exemple de fonction:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    def inv(n):
        data=1.0/n
        return data
     
    print inv(2.0)
    >0.5
     
    print inv(0.0)
    >Traceback (most recent call last):
      File "debugging01.py", line 10, in <module>
        print inv(0.0)
      File "debugging01.py", line 5, in inv
        data=1.0/n
    ZeroDivisionError: float division
    Le soucis de cette fonction c'est qu'elle ne traite pas le cas où n=0...
    On écrira donc pour le traiter:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    def inv(n):
        if n!=0.0:
            data=1.0/n
        else:
            data=False
        return data
     
    print inv(2.0)
    >0.5
     
    print inv(0.0)
    >False
    Ou avec le traitement des erreurs:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    retValue=inv(2.0)
    if retValue!=False:
        print retValue
    >0.5
     
    retValue=inv(0.0)
    if retValue!=False:
        print retValue
    >
    Note: J'ai conscience que dans certains cas, il est possible de recourir à des astuces. Par exemple, une fonction qui recherche la position d'un mot dans un texte, fournira une valeur entière en retour et en cas d'échec une valeur négative comme -1. La valeur d'une position ne pouvant jamais être négative, l'astuce ne limite en rien la fonction. Dans une tel cas la fonction retourne toujours des nombres entiers.
    Cependant, il n'est pas toujours possible de réserver une valeur spécifique de même type.


    On peut alors imaginer de retourner systématiquement un tableau de deux valeurs.
    La première donnée est le résultat de la fonction: a-t-elle fonctionné oui ou non.
    La seconde donnée est la valeur retournée elle-même, du moins si elle existe.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    def inv(n):
        state=False
        data=0.0
        if n!=0.0:
            state=True
            data=1.0/n
        return [state,data]
     
    retValue=inv(2.0)
    if retValue[0]:
        print retValue[1]
    >0.5
     
    retValue=inv(0.0)
    if retValue[0]:
        print retValue[0]
    >
    Ici l'avantage est de pouvoir séparer clairement les données retournées et le traitement des erreurs. Les valeurs ne sont plus mélangées, ce qui est mieux dans l'absolu pour le traitement des erreurs.

    Par contre, la récupération des données oblige à passer par des indices de tableau et il y a risque de confusion.
    J'ai volontairement introduit une erreur dans le code ci-dessus: le dernier 'print retValue[0]' n'a pas le bon indice (1 est correct). On voit qu'il est facile de se tromper.



    Donc voilà j'aurai aimé savoir comment vous faites dans vos programmes pour gérer ces cas particulier.

    Existe-t-il des techniques connues ou c'est la débrouille au cas par cas ?

  2. #2
    Expert éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 823
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 823
    Points : 7 119
    Points
    7 119
    Par défaut
    Toutes les réponses à tes questions sur la doc officielle
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  3. #3
    Membre éclairé
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Points : 751
    Points
    751
    Par défaut
    Salut,
    Deux cas pour moi,
    Soit la chaîne indiquée n'est pas dans le texte et dans ce cas la fonction retourne None (type null python)
    Soit, dans le cas de la division par zero, je considère qu'il est de la responsabilité du programmeur d'inclure l'appel à la fonction dans un bloc et dans ce cas dans le corps de la fonction je lève une exception avec dans le cas d'une division par zero.
    Tout dépend si c'est une erreur de logique (de division) qui interromp le programme ou une absence de résultat (pas le mot dans la chaîne) qui n'est pas vraiment une erreur.
    J'espère que je suis pas trop obscur

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2006
    Messages : 35
    Points : 21
    Points
    21
    Par défaut
    Oui oui vous êtes clairs mais en fait je me rend compte que mon exemple avec la division par zéro était un peu malheureux... C'est vrai que ça se traite par les exceptions du langage lui-même. Mauvais exemple donc. Sorry.

    Non les cas qui m'intéressent, ce n'est pas ceux-là, c'est tous les autres quand une fonction retourne habituellement un résultat d'un certain type mais que dans certains cas elle ne peut pas le retourner pour une raison x. C'est pas une erreur à proprement parler, juste des cas spéciaux de retour de fonction. Après le programme doit intercepter ça sans pour autant recourrir à un try...

    Prenons plutot l'exemple avec le mot pas trouvé. Si je retourne None. Je dois après créer un test pour savoir si la valeur retournée par la fonction est None ou une chaine de caractères. C'est ces cas-là qui m'intéressent. Parce que dans ce cas là, la fonction retourne des valeurs avec des types différents.

  5. #5
    Expert éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 823
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 823
    Points : 7 119
    Points
    7 119
    Par défaut
    Dans ce cas utiliser isinstance

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    isinstance(None, str)
    >>>False
    isinstance("bonjour", str)
    >>>True
    avec des if...else, on s'en sort très bien.
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  6. #6
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2006
    Messages : 35
    Points : 21
    Points
    21
    Par défaut
    Oui voilà c'est plus ce genre de traitement qui m'intéresse.
    Donc toi tu proposes isinstance pour tester le type et puis un if/else.


    Sinon voici un meilleur exemple de programme pour servir de base à la discution:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    def nextWord(theSentence,theWord):
    	array=theSentence.split()
    	retValue=None
    	if theWord in array:
    		idx=array.index(theWord)
    		idx+=1
    		if idx<len(array):
    			retValue=array[idx]
    	return retValue
    Il s'agit d'un programme qui donne le mot qui suit un mot clé dans une phrase

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    theSentence='Un petit exemple pour illustrer le truc'
    theWord='petit'
    print nextWord(theSentence,theWord)
    >exemple
     
    theWord='truc'
    print nextWord(theSentence,theWord)
    >None
     
    theWord='machin'
    print nextWord(theSentence,theWord)
    >None
    Trois cas possibles:
    1) le mot clé existe et le mot qui suit aussi, on retourne du texte
    2) le mot clé existe mais il n'y a pas de mot qui suit (dernier mot de la phrase)
    3) le mot clé n'existe pas, il n'y a donc pas de réponse non plus

    EDIT: on dit aussi que pour créer un programme avec le moins de bugs possible une fonction devrait toujours retourner un résultat du même type.
    Mais dans cet exemple, on voit bien que ça semble difficile dans la pratique...

    A moins peut être de passer par un tableau ? (comme expliqué dans le post original).
    Si vous avez d'autres idées que le tableau ou autre pour traiter ça, n'hésitez pas

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    105
    Détails du profil
    Informations personnelles :
    Âge : 56
    Localisation : Suisse

    Informations forums :
    Inscription : Septembre 2007
    Messages : 105
    Points : 145
    Points
    145
    Par défaut
    Bonjour,

    Il te suffit de tester la valeur retournée par ta fonction, si la valeur retournée est None le test échouera.
    Ce qui donne dans ton exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    theSentence='Un petit exemple pour illustrer le truc'
    for theWord in ['petit','truc','machin']:
        result = nextWord(theSentence,theWord)
        if result: print result
    La seule réponse que tu obtient est exemple.

    Salutations.

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2006
    Messages : 35
    Points : 21
    Points
    21
    Par défaut
    Merci cette petite astuce va me permettre d'alléger mon code :-)

    Donc avec un test IF, toute valeur quelque soit son type est considétée comme True, sauf la valeur False et None ? C'est bon à savoir ça.

    Juste pour tester, je lui ai demandé
    None==False
    et il me répond 'False' ce qui prouve que pour lui ce sont pourtant des valeurs différentes.

    ++

  9. #9
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    141
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2008
    Messages : 141
    Points : 184
    Points
    184
    Par défaut
    Salut !

    Citation Envoyé par arketip Voir le message
    Donc avec un test IF, toute valeur quelque soit son type est considétée comme True, sauf la valeur False et None ? C'est bon à savoir ça.
    En fait, sont considérés comme False, les valeurs "vides", à savoir :
    * 0 (entier nul);
    * 0.0 (flottant nul);
    * 0 + 0j (complexe nul);
    * [] (liste vide);
    * '' ou "" ou '''''' ou """""" (les différentes chaînes de caractères vides);
    * {} (dictionnaire vide) ;
    * set() (ensemble vide);
    * () (tuple vide) ;
    * None.

    Tu peux aussi rajouter, si tu importes les modules decimal et fractions :
    * decimal.Decimal(0) ;
    * fractions.Fraction(0).

    J'ai essayé d'être exhaustif, mais j'en oublie peut-être !

    Et pour ton test "False == None", essaie :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    >>> False == 0
    >>> 0 == None
    D'ailleurs, celui-là m'a toujours fait marrer :


    Ciao !

  10. #10
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2006
    Messages : 35
    Points : 21
    Points
    21
    Par défaut
    Merci pour toutes ces infos :-)

    Citation Envoyé par nardo47 Voir le message
    D'ailleurs, celui-là m'a toujours fait marrer :
    Lol

    Mmmmh puisque False==0 donne True
    mais que None==0 donne False.
    Quelle est la valeur de None ?

    Je crois que c'est foutu:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    >>> type(None)
    <type 'NoneType'>
     
    >>> type(False)
    <type 'bool'>
    Probablement que seul None a la Valeur None...

  11. #11
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    141
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2008
    Messages : 141
    Points : 184
    Points
    184
    Par défaut
    Exactement, None a 1 valeur bien définie, qui ne correspond à rien d'autre.

    Elle correspond à l'absence de valeur, c'est l'équivalent du null d'autres langages.

    Mais la liste des valeurs que je t'ai donnée est la liste des valeurs qui s'évaluent à False lors d'un test logique.
    En aucun cas, ils ne sont égaux à False, sauf False lui-même !

    C'est une facilité de codage, afin d'avoir des tests logiques + légers et + adaptables.

  12. #12
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2006
    Messages : 35
    Points : 21
    Points
    21
    Par défaut
    Tiens tant qu'on est dans les choses interdites, que penses-tu de ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    >>>False=True
    >>>if False: print "OK"
    ...
    OK
    Et voilà python transformé en YES MAN !
    On peut donc redéfinir False, certains diront que c'est mal... je ne sais pas :-)
    Par contre None ne se laisse pas redéfinir...

  13. #13
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    141
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2008
    Messages : 141
    Points : 184
    Points
    184
    Par défaut
    En réalité, tu n'as pas réelllement redéfini False. Tu as juste créé une variable qui s'appelle "False" et qui vaut "True".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    >>> if 2 > 3:
    ...     print 'false branch'
    ... else:
    ...     print 'true branch'
    ...
    'true branch'
    >>> False = True
    >>> if 2 > 3:
    ...     print 'false branch'
    ... else:
    ...     print 'true branch'
    ...
    'true branch'
    On peut voir ici que le "False = True" n'a aucune incidence sur le test logique effectué.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    # On sauvegarde les id des objets True et False avant la "redéfinition".
    >>> falseid = id(False)
    >>> trueid = id(True)
    >>> False = True
    >>> falseid == id(False)
    False
    >>> trueid == id(False)
    True
    >>> id(2 < 3) == trueid
    True
    >>> id(2 > 3) == falseid
    True
    Ici, on peut voir que "False" pointe désormais vers "True" (les id sont identiques), mais que les tests logiques ne seront pas impactés.

    Cela dit, c'est typiquement un code propre à enduire d'erreur, mais nous sommes sauvés, carpychecker est notre ami à tous : il relèvera toutes les erreurs de ce type là (et bien d'autres).

    Et pour None, je ne sais pas !

  14. #14
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    141
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2008
    Messages : 141
    Points : 184
    Points
    184
    Par défaut
    Citation Envoyé par nardo47 Voir le message
    Et pour None, je ne sais pas !
    En fait, si !

    None fait partie de la syntaxe du langage, pas les valeurs True et False.
    Ces 2 dernières valeurs sont juste des "habillages" des valeurs 1 et 0.

    Ce ne sont donc pas des mots réservés... sauf dans Python 3 !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    Python 3.1.1 (r311:74480, Oct 20 2009, 23:35:27) 
    [GCC 4.2.4 (Ubuntu 4.2.4-1ubuntu4)] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> False = True
      File "<stdin>", line 1
    SyntaxError: assignment to keyword

Discussions similaires

  1. Valeur de retour pour fonction
    Par oufou dans le forum Débuter
    Réponses: 7
    Dernier message: 19/09/2014, 16h02
  2. Réponses: 3
    Dernier message: 27/02/2012, 17h52
  3. Comment faites-vous pour récupérer la valeur d'une liste dynamique ?
    Par Cvbdev dans le forum Général JavaScript
    Réponses: 10
    Dernier message: 03/06/2010, 09h01
  4. Réponses: 8
    Dernier message: 14/12/2007, 17h12
  5. [Struts]comment faites-vous pour enregistrer..
    Par pouss dans le forum Struts 1
    Réponses: 7
    Dernier message: 30/09/2005, 12h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo