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 :

Bug de mémoire ou une logique qui m'échappe ?


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    aucune
    Inscrit en
    Juillet 2020
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : aucune

    Informations forums :
    Inscription : Juillet 2020
    Messages : 15
    Par défaut Bug de mémoire ou une logique qui m'échappe ?
    Bonjour,
    J'ai un problème avec les listes python :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    liste = list([]) #Je crée une liste
    liste.append(7854) #J'y met des valeurs au pif
    liste.append(4546) #J'y met des valeurs au pif
    liste.append(8514) #J'y met des valeurs au pif
     
    save = liste #Je crée une copie de la liste pour la manipuler sans modifier la liste de départ
     
    del save[0] #Je modifie la liste crash-test
     
    print(liste) #J'affiche l'ancienne liste pour vérifier si elle n'a pas changer
    #Resultat: liste = [[4546],[8514]]
     
    #ELLE A CHANGER !!!
    Je ne comprend pas !
    Par exemple sans liste ça ne fait pas ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    a = 0
    b = a
    b += 1
     
    print(a)
    #Resultat : a = 0 (Et non 1 !)
    Merci de votre aide
    Désolé la langue française que je maltraite... :)

  2. #2
    Invité
    Invité(e)
    Par défaut
    Il faut copier le contenu comme ci-dessus sinon save et liste sont "liées"...

  3. #3
    Membre averti
    Homme Profil pro
    aucune
    Inscrit en
    Juillet 2020
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : aucune

    Informations forums :
    Inscription : Juillet 2020
    Messages : 15
    Par défaut
    Citation Envoyé par LeNarvalo Voir le message
    Il faut copier le contenu comme ci-dessus sinon save et liste sont "liées"...
    Un grand merci !

    C'est quand même bizarre tout ça...

  4. #4
    Membre chevronné
    Homme Profil pro
    BTS SN IR
    Inscrit en
    Mai 2017
    Messages
    514
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : BTS SN IR

    Informations forums :
    Inscription : Mai 2017
    Messages : 514
    Par défaut
    Il existe des objects muttables et des objects immutables, un object muttable est souvent un object / type de donnée (suivant les langages où un tableau ne serait qu'une suite de pointeur) où l'on pourra faire quelque chose sans devoir le recréer entièrement.
    Un object immutable est un object dont on ne peux pas changer la valeur, on doit créer un nouvel object en mémoire.

    les variables ne sont que des étiquettes qui pointent sur des zones mémoires (d'où la notion de pointeur)

    quand vous faites a = 0; b=a; b+=1 voici ce qu'il se passe dans l'ordinateur (dans le cas général d'un langage quelconque ne procédant à aucune optimisation):

    je crée une zone mémoire où j'y met la valeur 0, cette zone mémoire à l'adresse 0xABCD1
    je dis que a pointe vers 0xABCD1

    Je regarde vers quoi pointe a
    je lis la valeur de la zone mémoire 0xABCD1qui vaut 0
    je crée une nouvelle valeur 0 dans la mémoire, elle a l'adresse 0xABCD2
    je dis que b pointe vers 0xABCD2

    Je regarde vers quoi pointe b
    je lis la valeur de la zone mémoire 0xABCD2 qui vaut 0
    je calcule 0+1
    je crée une nouvelle la valeur calculé dans la mémoire, elle a l'adresse 0xABCD3
    je dis que b pointe vers 0xABCD3

    Mais les langages sont intelligents, ils optimisent:
    ils vont faire pointer a et b vers la même zone mémoire sans même regarder la valeur
    ils ont un garbage collector, en gros ils vont désallouer les zones mémoires inutilisés (dans le cas de python c'est quand il n'y a plus d'étiquette sur une zone mémoire)
    ect ...


    Et c'est à cause de cette optimisation que vous tombez dans le piège, les "variables" (a et b) ne sont pas liées entre elles par l'affectation (b=a) mais par le faite qu'elle pointe sur la même zone mémoire. la liaison est donc dans le sens contraire

    Python est capable même d'aller assez loin dans l'optimisation:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    >>> a = "blabla"
    >>> hex(id(a))
    '0x7ff801359720'
    >>> b = "blabla"
    >>> hex(id(b))
    '0x7ff801359720'
    même si vous ne faites pas une affectation direct (b=a) l’interpréteur python va regarder s'il n'existe pas déjà "blabla" en mémoire, et si oui faire pointer b vers cet object

    par contre attention ce mécanisme n'est pas toujours utilisé car dans certains cas l'interpréteur conclu que ce sera tout aussi rapide de créer un nouvel object que de chercher s'il n'existe pas déjà
    les critères de si oui ou non il faut vérifier sont gigantesques, tou d'abord ça dépend de l’interpréteur (CPython, celui de base ou bien IronPython par exemple) du type d'architecture matériel, de l'object en question, ect

  5. #5
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 830
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 830
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par Personne3443 Voir le message
    Un grand merci !
    Il y a d'autres façons comme save=list(liste) (recréation d'une liste "à la volée" à partir de la variable "liste" et récupération de cette mémoire dans "save") ou bien save=liste[:] (utilisation des slices qui créent eux aussi des trucs en ram). Mais attention avec toutes ces méthodes car si la liste contient elle-même des éléments complexes (sous-listes, objets) alors on ne recopie que leurs "adresses".
    Sinon il existe un module "copy" qui contient la fonction "deepcopy" qui, elle, se charge de tout dupliquer en récursif.

    Citation Envoyé par Personne3443 Voir le message
    C'est quand même bizarre tout ça...
    990 fois sur 1000 on n'a pas besoin de dupliquer une liste (en effet, pouquoi faire ? La première ne suffit-elle pas ?).
    Sur les 10 fois qui restent, dans 9 cas la duplication de l'adresse suffit (et c'est plus rapide de copier une simple adresse que tout un contenu). Ne reste qu'une fois sur 1000 où tu auras besoin de dupliquer le contenu d'une liste. Perso je trouve le truc plutôt bien pensé.

    Citation Envoyé par flapili Voir le message
    Python est capable même d'aller assez loin dans l'optimisation:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    >>> a = "blabla"
    >>> hex(id(a))
    '0x7ff801359720'
    >>> b = "blabla"
    >>> hex(id(b))
    '0x7ff801359720'
    même si vous ne faites pas une affectation direct (b=a) l’interpréteur python va regarder s'il n'existe pas déjà "blabla" en mémoire, et si oui faire pointer b vers cet object
    En fait c'est encore plus subtil que ça. Tente hex(id("blabla")) et je suis certain que tu auras '0x7ff801359720'. Quand tu écris "blabla" dans ton code pour quelque raison que ce soit (ex print("blabla")) la chaine est alors créée une fois dans le tas et ensuite a="blabla" ne fait qu'affecter cette adresse à "a" (tout comme en C quand tu écris char *c="blabla"). Enfin c'est comme ça que je le vois.

    Mais ça ne fonctionne qu'avec des objets immuables (chaines, listes, ensembles). Si tu écris a=12345 puis b=12345 alors hex(id(a)) et hex(id(b)) n'auront pas la même valeur.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  6. #6
    Membre chevronné
    Homme Profil pro
    BTS SN IR
    Inscrit en
    Mai 2017
    Messages
    514
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : BTS SN IR

    Informations forums :
    Inscription : Mai 2017
    Messages : 514
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    En fait c'est encore plus fin que ça. Tente hex(id("blabla")) et je suis certain que tu auras '0x7ff801359720'. Quand tu écris "blabla" dans ton code pour quelque raison que ce soit (ex print("blabla")) la chaine est alors créée une fois dans le tas et ensuite a="blabla" ne fait qu'affecter cette adresse à "a" (tout comme en C quand tu écris char *c="blabla"). Enfin c'est comme ça que je le vois.
    C'est également comme ça que je le vois avec CPython, cependant si regarder si l'object n'existe pas déjà est un comportement commun aux différents interpréteurs à ma connaissance je ne mettrais pas ma main à couper que c'est le cas pour tous.

    De même ce mécanisme n'est pas toujours employé:
    sur mon destop (Python 3.8.0 (tags/v3.8.0:fa919fd, Oct 14 2019, 19:37:50) [MSC v.1916 64 bit (AMD64)] on win32

    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
    >>> a = "a"
    >>> a is "a"
    True
    >>> b = "b!"
    >>> b is "b!"
    False
    >>> "a" is "a"
    True
    >>> "foo" is "foo"
    True
    >>> "foo!" is "foo!"
    True
    >>> foo = "foo!"
    >>> foo2 = "foo!"
    >>> foo is foo2
    False
    >>> foo is "foo!"
    False
    >>> bar = "bar!"
    >>> bar2 = bar
    >>> bar2 is bar
    True
    Je sais que avec CPython le char ! induit se comportement, je ne sais pas si c'est le cas avec une version 2.x, ou Jython/IronPython/ect

    L'explication la plus détaillé que je connaisse est https://github.com/satwikkansal/wtfp...-explanation-2

  7. #7
    Membre averti
    Homme Profil pro
    aucune
    Inscrit en
    Juillet 2020
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : aucune

    Informations forums :
    Inscription : Juillet 2020
    Messages : 15
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    990 fois sur 1000 on n'a pas besoin de dupliquer une liste (en effet, pouquoi faire ? La première ne suffit-elle pas ?).
    Sur les 10 fois qui restent, dans 9 cas la duplication de l'adresse suffit (et c'est plus rapide de copier une simple adresse que tout un contenu). Ne reste qu'une fois sur 1000 où tu auras besoin de dupliquer le contenu d'une liste. Perso je trouve le truc plutôt bien pensé.
    C'est ma façon de coder qui ne doit pas être très optimiser ...
    En fait j'ai une base de données remplie de choix dans une liste. Il y a un choix a faire, certains choix ne sont plus possible a faire au moment de prendre la décision donc je copie la base de donnée et supprime les choix impossible pour gagner du temps dans la recherche du meilleur choix et garder ma base de donnée intacte pour les futures choix. C'est peut être moins optimiser mais plus claire pour moi.

    Merci de toute ces réponses, on en apprend tout les jours grâce a ... developpez.net

  8. #8
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 830
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 830
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Personne3443 Voir le message
    En fait j'ai une base de données remplie de choix dans une liste. Il y a un choix a faire, certains choix ne sont plus possible a faire au moment de prendre la décision donc je copie la base de donnée et supprime les choix impossible pour gagner du temps dans la recherche du meilleur choix et garder ma base de donnée intacte pour les futures choix.
    Ok, j'admets, tu entres dans le cas où tu dois copier ta liste (enfin quand tu dis "bdd" j'imagine que c'est la liste de départ dont tu parles, et que tu ne veux pas modifier, parce que si vraiment tu avais une vraie bdd alors on ne serait plus dans le cas d'une liste à copier).
    Il y a évidemment plusieurs façons de voir la chose mais perso je pense que moi je créerais la liste de choix à partir d'un traitement de la liste bdd initiale. Exemple
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    choix=[]
    for x in bdd:
    	if x autorisé à faire partie du choix: choix.append(x)
    print("Voici les choix autorisés : ", choix)

    Chose qu'on peut ensuite réduire grâce aux listes en intension: choix=tuple(x for x in bdd if x autorisé à faire partie du choix); print("Voici les choix autorisés : ", choix)

    Citation Envoyé par flapili Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    >>> b = "b!"
    >>> b is "b!"
    False
    Merde, chez-moi (Debian Buster, Python 3.7) c'est pareil !!! id(b) et id("b!") ne donnent pas le même résultat
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

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

Discussions similaires

  1. Premiers pas en JAVA et déjà une logique qui m'échappe.
    Par Jean-Jacques Engels dans le forum Débuter avec Java
    Réponses: 8
    Dernier message: 16/03/2010, 16h31
  2. [MySQL] Variable globale: une notion qui m'échappe
    Par Prosis dans le forum PHP & Base de données
    Réponses: 11
    Dernier message: 28/09/2007, 16h13
  3. Réponses: 13
    Dernier message: 05/03/2007, 09h29

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