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 :

liste non effacée de la memoire à la fin d'une fonction


Sujet :

Python

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2013
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2013
    Messages : 11
    Points : 5
    Points
    5
    Par défaut liste non effacée de la memoire à la fin d'une fonction
    Bonjour à tous,
    il y a un comportement de python que je ne comprend pas. J'aurais besoin de l'aide de plus calé que moi sur le sujet

    Le code ci dessous
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    def f(p=[0]):
        print(p)
        p.append(1)
     
    f()
    f()
    f()
    me renvoie

    [0]
    [0,1]
    [0,1,1]

    A chaque appel de la fonction, non seulement p n'est pas réinitialisé, mais en plus il garde la valeur qu'il avait lors de l'appel précédent.
    Du coup, je ne comprend pas, je pensais qu'à la fin d'une fonction, toutes ses variables locales étaient éffacées. Pourquoi est-ce que lors de chaque appel, p pointe vers la même liste et pourquoi cette liste n'est pas effacée de la memoire à la fin de l'execution de f ?
    De plus pourquoi la valeur par defaut p=[0] est-elle ignorée lors des second et troisième appel de f ?

    Si on remplace p.append(1) par p=p+[1], le problème ne se pose plus. Le code renvoie bien [0],[0] et [0]

    Merci d'avance

  2. #2
    Expert éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 817
    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 817
    Points : 7 110
    Points
    7 110
    Par défaut
    Il faut regarder du côté des appels par valeur et des appels par référence. Dans le cas d'une liste c'est un objet python (PyObject *), on a donc passé en argument sa référence.

    Je ne comprend pas bien ce que tu essayes de faire avec ton code, c'est quoi le but ? Car il est peu courant d'avoir envie de faire ce genre de chose...

    Dans ton cas si tu veux supprimer la référence on utilisera del

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    def f(p=[0]):
        print(p)
        del(p)
     
     
    f()
    f()
    f()
    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
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    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 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Salut,

    C'est une des "facéties" de Python qui étonne tout débutant au moins une fois.
    La raison est que les fonctions sont de vrais objets.
    Leur définition n'est évaluée qu'une seule fois et les paramètres par défaut sont des données qui feront partie de l'objet "function" crée lorsque l'interpréteur rencontre "def".

    Le soucis est lorsque qu'on a affaire à des "mutables" comme les "list".
    La même "list" sera utilisée d'appels en appels... et les appends vont s'accumuler...

    Si ce n'est pas ce que vous voulez, il faut écrire (par exemple):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    def f(p=None):
        p = p or [0]
        print(p)
        p.append(1)
        print(p)
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2013
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2013
    Messages : 11
    Points : 5
    Points
    5
    Par défaut
    Bonjour fred et merci pour ta réponse.
    Ce code n'a strictement aucun interet, il est juste là pour illustrer un problème que je ne comprend pas ( et que j'ai rencontré dans un "vrai" programme ce coup ci )

    J'ai essayé
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    def f(p=[]):
        print(p)
        p.append(1)
        del(p)
     
    f()
    f()
    f()
    Mais ca ne change rien.

    Grace à ton aide, j'ai su où chercher et j'ai trouvé un élément de réponse . Quand on utilise une valeur par défaut, la référence à l'objet va rester la même pour toute la durée du programme.
    Donc si j'ai bien compris, mon premièr appel de f() fait pointer p sur la liste [0]. La liste étant mutable p.append(1) modifie cet liste en [0,1]. Lors du deuxième appel de f(), la référence étant la même, p va pointer sur la liste [0,1] (la liste [0] qui a été modifié).
    Avec la version du programme qui utilise p=p+[1], p va référencer une autre liste et la liste initiale et donc lors des prochains appels, on retrouve bien la liste [0]
    Pfiouuuu, ultra-vicieux comme truc. Je vais retenir la moralité du lien que j'ai donné plus haut : « Bref, évitez les mutables dans les paramètres par défaut à moins de savoir ce que vous faites »

    J'ai trouvé une petite astuce pour avoir un autre code qui fonctionne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    def f(p=None):
        if p == None: p = []
        print(p)
        p.append(1)

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juin 2013
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2013
    Messages : 11
    Points : 5
    Points
    5
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Salut,

    C'est une des "facéties" de Python qui étonne tout débutant au moins une fois.
    La raison est que les fonctions sont de vrais objets.
    Leur définition n'est évaluée qu'une seule fois et les paramètres par défaut sont des données qui feront partie de l'objet "function" crée lorsque l'interpréteur rencontre "def".

    Le soucis est lorsque qu'on a affaire à des "mutables" comme les "list".
    La même "list" sera utilisée d'appels en appels... et les appends vont s'accumuler...

    Si ce n'est pas ce que vous voulez, il faut écrire (par exemple):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    def f(p=None):
        p = p or [0]
        print(p)
        p.append(1)
        print(p)
    - W
    Oups je n'avais pas vu ton post avant d'écrire le mien.
    Merci pour ta réponse, ça corrobore ce que j'ai compris.

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

Discussions similaires

  1. Attendre la fin d'une fonction
    Par benjhe dans le forum VB.NET
    Réponses: 4
    Dernier message: 13/12/2007, 14h44
  2. Réponses: 4
    Dernier message: 16/01/2007, 13h42
  3. Réponses: 3
    Dernier message: 18/09/2006, 12h35
  4. Réponses: 4
    Dernier message: 31/08/2006, 11h25
  5. garder en memoire un resultat d'une fonction
    Par khadidja dans le forum C++
    Réponses: 6
    Dernier message: 26/07/2004, 14h52

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