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 :

problème d'une valeur de paramètre dans une fonction récursive


Sujet :

Python

  1. #1
    Membre émérite
    Homme Profil pro
    Inscrit en
    Janvier 2006
    Messages
    491
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Corse (Corse)

    Informations forums :
    Inscription : Janvier 2006
    Messages : 491
    Par défaut problème d'une valeur de paramètre dans une fonction récursive
    bonjour ,
    j'ai voulu faire une fonction récursive qui renvoie une suite syracuse
    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
    18
    19
    def syracuse(n,resultat=[]):
     
        resultat.append(n)
        if n==1:
            return resultat
     
        else:
            if n%2==0:
                syracuse(n/2,resultat)
     
            else:
                syracuse(3*n+1,resultat)
            return resultat
     
     
    if __name__=="__main__":
     
        print syracuse(17)
        print syracuse(17)
    j'obtiens comme resultat au premier print:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    [17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
    qui est le résultat attendu , mais lors du deuxième print j'obtiens:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    [17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
    et je ne comprends pas ... pourquoi le paramètre resultat la deuxième fois garde en mémoire la valeur du premier appel de la fonction?

  2. #2
    Membre Expert
    Homme Profil pro
    Enseignant
    Inscrit en
    Juin 2013
    Messages
    1 617
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2013
    Messages : 1 617
    Par défaut
    C'est à cause de la variable resultat qui n'est pas renseignée mais qui prend la valeur par défaut précédente.

    remplacer par print(syracuse(17,[ ])

  3. #3
    Membre émérite
    Homme Profil pro
    Inscrit en
    Janvier 2006
    Messages
    491
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Corse (Corse)

    Informations forums :
    Inscription : Janvier 2006
    Messages : 491
    Par défaut
    Merci Marcoc056,
    mais justement ce que je ne comprends pas c'est pourquoi le paramètre résultat prend la valeur précédente

  4. #4
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 741
    Par défaut
    Salut,

    C'est une fonctionnalité de Python qui surprend les débutants la première fois seulement.
    Le soucis est d'avoir un objet dit "mutable" (une list ou un dict) comme paramètre par défaut:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    >>> def func(default=[]):
    ...     default.append('X')
    ...     return default
    ...
    >>> func()
    ['X']
    >>> func()
    ['X', 'X']
    Si vous lisez la documentation, vous y trouveriez que les paramètres par défaut d'une fonction sont construits et assignés lors de la définition de la fonction et non à chaque appel de la fonction. Si l'objet est "mutable", la modification "persiste".
    La solution générale est d'éviter d'avoir des "mutables" en les initialisant explicitement:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    def syracuse(n, resultat=None):
        if resultat is None: 
              resultat = []
        resultat.append(n)
        ...
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Membre émérite
    Homme Profil pro
    Inscrit en
    Janvier 2006
    Messages
    491
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Corse (Corse)

    Informations forums :
    Inscription : Janvier 2006
    Messages : 491
    Par défaut
    merci wiztricks pour l'explication
    et j'en profite pour souhaiter une bonne année à tout le monde

  6. #6
    Expert confirmé

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 307
    Par défaut
    Salut,

    Utiliser une liste vide en argument amène souvent à des résultats déconcertants.

    Il y a souvent moyen d'éviter de le faire, par exemple:
    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
    18
    19
    20
     
    def syracuse(n):
        global resultat
        resultat.append(n)
        if n == 1:
            return resultat
     
        else:
            if not n % 2:
                syracuse(n/2)
     
            else:
                syracuse(3*n+1)
        return resultat
     
    if __name__=="__main__":
        resultat = []
        print syracuse(17)
        resultat = []
        print syracuse(21)

  7. #7
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Citation Envoyé par wiztricks Voir le message
    C'est une fonctionnalité de Python qui surprend les débutants la première fois seulement.
    Je considère toujours ça comme une anomalie de Python: quand on appelle une fonction sans citer son argument nommé, il devrait prendre sa valeur par défaut, même si c'est une liste! Imaginons qu'il y ait plein d'exceptions comme ça, et on ne sait plus programmer...

    Mais c'est comme ça et on fait avec. D'ailleurs, pylint détecte la présence d'un argument nommé avec une valeur liste comme un problème, et c'est très bien ainsi!

    En ce qui me concerne, voilà la solution que je préfère et qui ne demande qu'une seule ligne supplémentaire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def syracuse(n, resultat=None):
     
        resultat = resultat or [] # <= ligne indispensable pour que resultat=[] si None
     
        resultat.append(n)
        if n==1:
            return resultat
         else:
            if n%2==0:
                syracuse(n//2, resultat)
             else:
                syracuse(3*n+1, resultat)
            return resultat

  8. #8
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 741
    Par défaut
    Citation Envoyé par tyrtamos Voir le message
    Je considère toujours ça comme une anomalie de Python: quand on appelle une fonction sans citer son argument nommé, il devrait prendre sa valeur par défaut, même si c'est une liste! Imaginons qu'il y ait plein d'exceptions comme ça, et on ne sait plus programmer...
    Ce sujet a été, et est toujours le sujet de discussions passionnées.

    Dans d'autres langages, les fonctions se réduisent à du code: une liste d'instructions qui récupère des paramètres, mouline un truc et retourne un résultat.
    Avec Python, elles ne se réduisent pas à du code mais ont aussi un état (dont la liste des paramètres par défaut). Ce qui en fait de vrais objets... et çà devient de suite un peu plus compliqué que la simple fonction qu'on rencontre ailleurs.
    Il n'y a pas d'exceptions: tout est objet! Mais çà a des conséquences ou des implications étranges (et qui nous dérangent) dans certains cas.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 0
    Dernier message: 18/02/2014, 16h37
  2. Donner une valeur à un paramètre dans un reportviewer
    Par royal38 dans le forum Général Dotnet
    Réponses: 2
    Dernier message: 04/01/2014, 13h19
  3. Réponses: 1
    Dernier message: 26/12/2010, 21h20
  4. supprimer "entrer une valeur de paramètre" dans un formulaire
    Par Noline dans le forum Requêtes et SQL.
    Réponses: 6
    Dernier message: 24/08/2010, 17h19
  5. Réponses: 6
    Dernier message: 14/02/2006, 20h53

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