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 de surcharge avec dictionnaire [Python 2.X]


Sujet :

Python

  1. #1
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2015
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2015
    Messages : 9
    Par défaut Problème de surcharge avec dictionnaire
    Bonjour,

    J'ai un problème avec le système de surcharge lorsque l'un des élements clé est un dictionnaire.

    Je ne sais même pas comment décrire le problème parce que je ne comprend pas du tout son origine, donc voici un exemple:

    J'ai crée une fonction qui remplit le dictionnaire var en fonction d'un entier n.
    Cette fonction crée des clés égales aux entiers de 0 à n (exclu) ayant pour valeurs ces mêmes entiers.
    - Si la clé i existe déjà, la fonction affiche i == i
    - Sinon elle affiche i <- i
    - Si var n'est pas précisé, la fonction travaille (normalement) sur le dictionnaire vide {}


    Voici le code:

    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
    def fun(n, var = {}):
        print "\nCalling fun for n =", n
        for i in range(n):
            if i in var:
                print i, "==", i
            else:
                var[i] = i
                print i, "<-", i
        #del var
     
    fun(2)
    fun(5)
    fun(5)
    fun(5, var = {})
    fun(5)
    On remarque cependant que lorsque l'on ne précise pas le dictionnaire var, le dernier dictionnaire var crée est réutilisé.
    Je trouvais cela bizarre et j'ai donc ajouté la ligne en commentaire (del var) détruisant le dictionnaire à la fin de la fonction, cela n'a rien changé.
    Je me dis qu'il y a peut être un système de cache ou je ne sais pas...

    Quelqu'un peut il m'expliquer ce qu'il se passe ?

    Merci d'avance pour vos réponses.

  2. #2
    Expert confirmé

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

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

    Les objets mutables sont passés par référence, en créant cet objet dans les arguments de la fonction tu crées une confusion.

    En modifiant le print on peut le voir
    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
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     
    >>> def fun(n, var={}):
    ...     print 'Call with: %s, %s' %(n, var)
    ...     for i in range(n):
    ...             if i in var:
    ...                     print '%s in var' % i
    ...             else:
    ...                     var[i] = i
    ...                     print '%s -> var' % i
    ... 
    >>> fun(2)
    Call with: 2, {}
    0 -> var
    1 -> var
    >>> fun(5)
    Call with: 5, {0: 0, 1: 1}
    0 in var
    1 in var
    2 -> var
    3 -> var
    4 -> var
    >>> fun(7)
    Call with: 7, {0: 0, 1: 1, 2: 2, 3: 3, 4: 4}
    0 in var
    1 in var
    2 in var
    3 in var
    4 in var
    5 -> var
    6 -> var
    >>> fun(3, var={})
    Call with: 3, {}
    0 -> var
    1 -> var
    2 -> var
    >>> fun(5)
    Call with: 5, {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6}
    0 in var
    1 in var
    2 in var
    3 in var
    4 in var
    >>>
    Si ton besoin est de choisir de créer un nouveau dictionnaire ou de compléter un dico existant, il est préférable de le créer en premier lieu.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    def fun(n, var):
        ...
     
    dico = {}
    fun(5, dico)
    fun(7, dico)
    dico_1 = {}
    fun(8, dico_1)
    ...

  3. #3
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2015
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2015
    Messages : 9
    Par défaut
    Merci beaucoup pour ta réponse,

    Je ne comprends cependant par pourquoi la réference est conservée, quand bien même on supprime l'objet à la fin de l'appel.

  4. #4
    Expert confirmé

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 305
    Par défaut
    Les arguments de la fonction sont évalués une seule fois, lors de la compilation en bytecode. Ce qui induit ce comportement avec les objets mutables.

    https://docs.python.org/3/reference/....html#function
    Default parameter values are evaluated from left to right when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same “pre-computed” value is used for each call. This is especially important to understand when a default parameter is a mutable object, such as a list or a dictionary: if the function modifies the object (e.g. by appending an item to a list), the default value is in effect modified. This is generally not what was intended. A way around this is to use None as the default, and explicitly test for it in the body of the function

  5. #5
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2015
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2015
    Messages : 9
    Par défaut
    D'acc merci beaucoup !

  6. #6
    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 MrFlash03 Voir le message
    Je ne comprends cependant par pourquoi la référence est conservée, quand bien même on supprime l'objet à la fin de l'appel.
    Parce que le "del var" est placé à l'intérieur de la fonction. D'après ce que je comprends, l'argument "var" de la fonction est une variable interne qui pointe sur les mêmes données que la variable globale "var". En supprimant la variable interne "var", les données ne sont pas perdues et continues à être pointées par la variable globale var, et c'est grâce à ça qu'elle est modifiée par la fonction.

    Personnellement, je n'aime pas beaucoup exploiter le passage par référence, sauf exception. Je préfère travailler à l'intérieur des fonctions avec une copie des données, et retourner la nouvelle valeur à la fin de la fonction avec "return". En bref, je préfère que mes fonctions soient "étanches". En contrepartie, pour des données très grosses, on perd un peu de temps à faire les copies.

  7. #7
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 697
    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 697
    Par défaut
    Salut,

    Citation Envoyé par MrFlash03 Voir le message
    Je ne comprends cependant par pourquoi la référence est conservée, quand bien même on supprime l'objet à la fin de l'appel.
    Lorsque vous écrivez "del var" vous vous contentez de supprimer l'étiquette "var" dans l'espace de nom (ici "local" à la fonction). L'objet associé à "var" ne sera supprimé que s'il n'y a plus de référence. Et comme la "déclaration" de la fonction garde une référence à cet objet là... il n'est pas supprimé.
    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    >>> a = 2
    >>> b = a
    >>> del b
    >>> b
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'b' is not defined
    >>> a
    2
    Si vous ne pouvez pas supprimer la référence, vous pouvez néanmoins remettre à zéro l'objet associé:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    >>> def foo(n, z={}):
    ...     z[n] = None
    ...     print (z)
    ...     z.clear()
    >>> foo(2)
    {2: None}
    >>> foo(3)
    {3: None}
    Mais avoir des arguments par défaut qui soient "mutables" est une pratique à éviter.

    - 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. Problème de surcharge d'opérateur flux avec pointeur
    Par eleve_prog dans le forum Débuter
    Réponses: 4
    Dernier message: 18/04/2011, 18h41
  2. problème de requête avec jointures
    Par tinhat dans le forum Requêtes
    Réponses: 7
    Dernier message: 11/08/2003, 10h33
  3. Problème dans requête avec count()
    Par BadFox dans le forum Requêtes
    Réponses: 3
    Dernier message: 08/07/2003, 18h02
  4. [Kylix] problème compilation kylix3 avec redhat 9.0
    Par madininaoursa dans le forum EDI
    Réponses: 1
    Dernier message: 02/07/2003, 16h21
  5. Problèmes de versions avec Xalan, Xerces et Java
    Par honeyz dans le forum XML/XSL et SOAP
    Réponses: 4
    Dernier message: 05/06/2003, 10h18

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