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 compréhension du fonctionnement de del et des references ou copie


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Avril 2004
    Messages : 574
    Par défaut Problème de compréhension du fonctionnement de del et des references ou copie
    Bonjour,

    Je suis en train de développer une application utilisant Tkinter pour afficher divers articles dans une fenêtre.
    Chaque article est affiché à l'aide d'un label et d'une image par exemple.
    En fait j'ai une liste myElems dans laquelle je place tous ce que je vais devoir afficher.

    Par exemple myElems = [MyLabel, MyButtonImage, MyLabel2, MyButtonImage2...]

    Sachant que MyLabel étends par exemple la classe Tkinter.Label...

    Bref, ensuite je passe cette liste à une classe "Agenceur" qui dispose correctement tous mes éléments dans un frame (par exemple, je peux préciser combien je veux d'élement par colone et par ligne... je peux changer la couleur d'une ligne sur deux, etc...).

    Bref !

    Lorsque que de grosse modification sont réalisés quelque part, je recharge entièrement tous les articles.
    Pour cela, je fais d'abord un del myElems [:]
    Mais je n'ai pas le sentiment que la mémoire est vraiment relachée ! Car au bout d'un moment, très rapide, mon application plante pour cause qu'elle "ne peut pas allouer de mémoire pour bitmap".

    J'ai donc surchargé les fonction __del__ de ma classe MaLabel dans laquelle je mets juste un print pour voir si je passais bien dedans.

    Et je n'y passe pas en cours d'application. Si je ferme mon application avant qu'elle ne plante pour cause d'espace mémoire insuffisant, alors j'ai bien mes print qui sont réalisés.

    Venant du C++, j'ai du mal à comprendre quand le garbage collector fait son travail, si il est possible de le forcer à réaliser une libération d'espace mémoire immédiate...
    Ensuite, je souhaiterais savoir si lorsque l'on vide une liste, elle supprime automatiquement tous ces objets. Par exemple, si on les a passé avant à une autre liste, il ne devrait pas le faire ?
    Comment se passe exactement les transferts d'un objet dans une autre liste.
    Est ce une copie réelle ou alors il pointe vers la même référence ??

    Merci de m'éclairer sur ces points si c'est possible ...

    Par exemple, j'ai fait un simple text dans mon main :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    root = Tkinter.Tk()
    label = MyLabel(root)
    del label
    et c'est tout et je ne passe pas dans ma fonction del puisque rien n'est affiché... ???!!!

  2. #2
    Membre Expert

    Homme Profil pro
    Diverses et multiples
    Inscrit en
    Mai 2008
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Diverses et multiples

    Informations forums :
    Inscription : Mai 2008
    Messages : 662
    Par défaut
    À l’exception de types de base (int, str, float, …), et plus généralement de tous les types immutable (cela inclue les tupples, par ex.), tous les objets pythons sont toujours copiés/passés par référence (si on veut une «*vraie*» copie, il faut utiliser deepcopy).

    Tout cela est géré par un compteur de référence –*faire une copie incrémente de 1 le compteur de l’objet, supprimer une copie le décrémente de 1. Donc, del se contente de décrémenter ce compteur. La réelle suppression de l’objet n’a lieu que quand ce compteur atteint 0, et c’est seulement à ce moment que l’optionnelle __delete__() est appelée…

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Avril 2004
    Messages : 574
    Par défaut
    Compris.

    Donc peut être que le soucis bien de la gestion avec Tkinter.
    J'ajoute un élément dans mon grid. par elem.grid(....)

    Juste avant de supprimer mon élément je fais :
    elem.grid_forget()
    del elem

    Mais je ne rentre pas dans ma fonction __del__

    Peut être que Tkinter conserve encore des références...
    Comment être sur qu'il n'en ait plus ?

  4. #4
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    Bonjour,

    La méthode pour détruire un Widget c'est .destroy()
    Les méthodes *forget des gestionnaires de géométrie ne fonts que 'retirer' le Widget de la géométrie.
    del(elem) ne fait que détruire la référence pour Python (comprendre la supprimer du namespace).
    Un Widget n'a pas besoin d’être nommer pour exister pour l'interpréteur Tcl/Tk.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    root = Tk()
    Button(root, command=root.quit, text='Quit').pack()
    root.mainloop()
    @+

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Avril 2004
    Messages : 574
    Par défaut
    Désolée, mais ce n'est pas très clair...

    Cela signifie que si j'ai une liste d'élément tels que : Tkinter.Label, Tkinter.Button, etc... et que je veux les supprimer pour toujours, il faudrait que je fasse :

    label = Tkinter.Label(frame, text="pouet")
    label.grid(row=1, column=2)

    ...

    label.grid_forget()
    label.destroy()

    ??

    Oui, merci, je viens de tester c'est bien ça !
    Il faut label.destroy()
    et del list[indiceDuLabel]

    Merci beaucoup pour votre aide !

  6. #6
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut
    La surcharge n'est sans doute pas la plus mauvaise idée (Comprendre mettre le destroy() dans __del__()).
    Le .*_forget() est inutile.

    Une chose a connaître dans votre cas:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    >>> import Tkinter
    >>> root = Tkinter.Tk()
    >>> l1 = Tkinter.Label(root, text='Label1')
    >>> l1.pack()
    >>> Tkinter.Label(root, text='Label2').pack()
    >>> def lab_destroy():
    ...     for Widget in root.winfo_children(): # <<<<<<<
    ...         if isinstance(Widget, Tkinter.Label):
    ...             Widget.destroy()
    ... 
    >>> Tkinter.Button(root, text='Destroy', command=lab_destroy).pack()
    >>> Tkinter.Button(root, text='Root Destroy', command=root.destroy).pack()
    >>> root.mainloop()
    C'est ce qui se passe avec .destroy(), lorsque un 'Widget' est .destroy() ses enfants aussi. A vous de trouver la 'boite' (plagia, je sais) qui vas bien dans votre géométrie. Frame est bien sur le conteneur par excellence.

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

    En fait __del__ n'est appelé qu'à la destruction de l'objet, çàd via le garbage collector lorsqu'il n'y plus de références.
    Lorsqu'on écrit:

    label = Tkinter.Label(frame, text="pouet")

    on crée une référence (label) à une instance de Label mais derrière l'appel, la bibliothèque tk ajoute le label dans la liste des .children de "frame".
    "del label" décrémentera le nombre de références à l'instance mais sans le .destroy la référence dans .children restera
    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    >>> import Tkinter as tk
    >>> r = tk.Tk()
    >>> class Label(tk.Label):
    ...     def __del__(self): print 'foo'
    ...
    >>> l = Label(r, text='xxx')
    >>> l.pack()
    >>> l.destroy()  # une référence en moins...
    >>> del l           # une autre référence...
    foo                   # maintenant çà passe dans __del__
    Tout çà pour dire que la lecture de:
    Chaque article est affiché à l'aide d'un label et d'une image par exemple. En fait j'ai une liste myElems dans laquelle je place tous ce que je vais devoir afficher.

    Par exemple myElems = [MyLabel, MyButtonImage, MyLabel2, MyButtonImage2...]

    Sachant que MyLabel étends par exemple la classe Tkinter.Label...
    m'incite à vous suggérer d'utiliser la "liste" interne à un widget Frame - puisqu'il s'agit de l'ensemble (voire de la hiérarchie) des objets crées dedans - lorsque vous devez "détruire" la liste, vous détruisez la frame... et la liste d'objets qu'elle contient.

    Note: la création restera label = Tkinter.Label(frame, text="pouet").

    Bon courage
    - 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. [MCD] Problème de compréhension du fonctionnement d'un héritage.
    Par Maverick57 dans le forum Schéma
    Réponses: 3
    Dernier message: 13/01/2012, 09h22
  2. [AJAX] Compréhension du fonctionnement d'ajax
    Par kikou732 dans le forum AJAX
    Réponses: 1
    Dernier message: 18/12/2011, 09h32
  3. [Portlet] [Fonctionnement] Problème de compréhension
    Par Bichette12 dans le forum Portails
    Réponses: 3
    Dernier message: 17/07/2009, 14h48
  4. Réponses: 1
    Dernier message: 31/08/2007, 09h23
  5. [C#] Problème de compréhension du fonctionnement d'un Timer
    Par cyllix dans le forum Windows Forms
    Réponses: 2
    Dernier message: 26/07/2006, 17h58

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