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 :

[Destructeur] avec des references sur un autre objet


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 562
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 562
    Par défaut [Destructeur] avec des references sur un autre objet
    bonjour,
    je ne suis pas un pro du python mais j'ai voulu faire un notificateur a la mode event du c# (enfin en version plus simple)
    bref
    j'ai ce 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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    class Updater:
        fluxs = []
     
        def __init__(self, parking, pkname, logger = None):
            print("> Updater constructeur")
            self.name = pkname
            self.onPark = parking['OnPark']
            self.totalPark = parking['TotalPark']
            self.logger = logger
     
        def __del__(self):
            print("> Updater descturcteur")
            self.__save()       
     
        def __iadd__(self, fluxToAdd):
            if not issubclass(fluxToAdd.__class__, BaseRunningFlux):
                raise Exception(f"{fluxToAdd.__class__.__name__} n'herite pas de BaseRunningFlux")
            fluxToAdd.notifyFunc = self.changed
            self.fluxs.append(fluxToAdd)
            return self
     
      def __save(self):
            if os.path.exists(self.name):
                try:
                    with open(self.name , 'w') as f:           
                        f.write(f"{{\n")
                        f.write(f"\t\"OnPark\": {self.onPark},\n")
                        f.write(f"\t\"TotalPark\": {self.totalPark}\n")
                        f.write(f"}}\n")
                        f.close()
                except Exception as error:
                    raise error
    j'ai pas mis tt la classe le reste est sans importance
    bref quand j'ajoute un objet qui hérite de BaseRunningFlux je lui colle une fonction pour qu'il me notifie ses changements de valeur a la classe parent via sa fonction changed

    avec un truc dans ce style
    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
    class BaseRunningFlux:
     
        @abstractmethod
        def __init__(self):
            self.notifyFunc = None
            self.count = 0
     
        def __del__(self):
            self.notifyFunc = None
     
        @property
        def notifyFunc(self):
            return self._notifyFunc
     
        @notifyFunc.setter
        def notifyFunc(self, value):
            self._notifyFunc = value
     
        @property
        def count(self):
            return self._count
     
        @count.setter
        def count(self, value):
            self._count = value
            if not self.notifyFunc is None: self.notifyFunc(self)
     
        def reset(self):
            self._count = 0
     
    class RunnigFlux(BaseRunningFlux):
     
        def __init__(self):
            BaseRunningFlux.__init__(self)
    sauf que quand je fais un del sur ma classe
    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
     upd = Updater(parking, parkname)
        print(f"etat parking : {upd}")
     
        f = RunnigFlux()
        f.count = 5
        upd += f
        print(f"etat parking : {upd}")
     
        f = RunnigFlux()
        f.count = -3
        upd += f
        print(f"etat parking : {upd}")
     
        print()
        print("test ajouter par ++")
        f.count += 1
        f.count += -1
     
        # Reinit
        print()
        print()
        reinit = 12
        print(f"REINIT a {reinit}")
        upd.reinit(reinit)
        print(f"etat parking : {upd}")
     
        #upd += Dummy()
     
        print("avant destructeur")
        del upd
        print("apres destructeur")
    il n'est pas réalisé a ce moment la mais a la fin du logiciel
    or comme je sauve un fichier la fonction open ne plus accessible
    et si je désactive la ligne #fluxToAdd.notifyFunc = self.changed
    la le del est fait a ce moment la

    bref je comprends pas trop

  2. #2
    Membre Expert
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 562
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 562
    Par défaut
    Update :

    en ajoutant la fonction clear a updater comme ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     def clear(self):
            for f in self.fluxs:
                f.notifyFunc = None
    et en l'appelant AVANT le del
    ca fonctionne

    mais je trouve ca pas super propre
    en fait faudrait un previous del pour pouvoir le faire avant le del effectif

    en fait c'est comme si la ramasse miette voulais supprimer l'objet updater de chacun des flux ....
    mais vu que je maitrise pas vraiment les concepts python ...

    bref si vous aviez une solution sexy

  3. #3
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 833
    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 833
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par ikeas Voir le message
    bref je comprends pas trop
    Ton code n'est pas reproductible. Ligne upd = Updater(parking, parkname) la variable "parking" n'existe pas. Je tente quand-même en y mettant un dico (j'ai vu que c'était utilisé comme ça) mais ensuite fluxToAdd.notifyFunc = self.changed alors que self.changed n'existe pas. Si le __init__ existe, ce n'est pas pour des prunes. C'est pour qu'on y crée les attributs de l'objet.
    Accessoirement je ne vois pas pourquoi tu mets self.notifyFunc = None dans le __del__ (tu remplis un attribut d'un objet qui va être détruit )

    Quand on veut comprendre ce qui se passe, on écrit des codes simples.
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class Updater:
    	def __init__(self, x):
    		print("%s.__init__(%s)" % (self, x))
    		self.x=x
     
    	def __del__(self):
    		print("%s.__del__()" % self)
     
     
    print("1")
    toto=Updater(123)
    print("2")
    #titi=toto
    del toto
    print("3")
    Avec ce code, on a le résultat suivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    1
    <__main__.Updater object at 0x7f79b61b0820>.__init__(123)
    2
    <__main__.Updater object at 0x7f79b61b0820>.__del__()
    3
    Si on décommente le #titi=toto, on a le résultat suivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    1
    <__main__.Updater object at 0x7ffbe3dec820>.__init__(123)
    2
    3
    <__main__.Updater object at 0x7ffbe3dec820>.__del__()
    Si on va plus loin...
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    print("1")
    toto=Updater(123)
    titi=toto
    print("2")
    del toto
    print("3")
    del titi
    print("4")
    ... on obtient le résultat suivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    1
    <__main__.Updater object at 0x7efe44001e10>.__init__(123)
    2
    3
    <__main__.Updater object at 0x7efe44001e10>.__del__()
    4
    On en conclut que tant que toto est référencé quelque part, le "del" ne se fait pas. Il faut que sa référence disparaisse (comme avec le del titi) pour que son del à lui se fasse. En fait Python travaille par "comptage de références" pour savoir quand libérer l'objet.

    Citation Envoyé par ikeas Voir le message
    or comme je sauve un fichier la fonction open ne plus accessible
    bref si vous aviez une solution sexy
    Tu ne peux pas savoir quand le del sera réellement fait (si un autre user récupère ton objet tu l'as dans l'os) donc tu ne peux pas te caler dessus pour sauver ton fichier. Pourquoi ne pas créer une fonction dédiée à la sauvegarde que tu appelles manuellement avant de faire le del? En plus tu pourras offrir à l'utilisateur une option "sauvegarder en cours" comme on a le ctrl-s sous Word ou Excel. Moi dans mes objets principaux, très peu redéfinissent le __del__ mais ils ont tous une méthode clear() et une méthode close() que j'appelle systématiquement à la fin de mon progamme.
    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]

  4. #4
    Membre Expert
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 562
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 562
    Par défaut
    pour le __del__ en effet c'était pour tester

    donc si j'ai bien compris tant qu'une ref existe quelque part l'objet n'est pas ramassé
    même si la référence est sur une fonction de l'objet et pas sur l'objet lui même

    évidement j'ai résolu le probleme en rajoutant une fonction dispose dans Updater
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
       def dispose(self):  
            self.__save()
            for f in self.fluxs:
                f.notifyFunc = None
    mais je pensais que l'appel explicite par le biais de del upd forcait l'appel du destructeur
    en fait c'est ce qu'on fait en c++ ou en c#

  5. #5
    Membre Expert
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 562
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 562
    Par défaut
    ce qui est paradoxale pour moi qui vient d'autres langage c'est de voir comment le ramasse miette fonctionne
    je pensais (sans doute naïvement) que tout ce qui était crée dans un bloc,

    une fonction par exemple comme celle que j'ai indique et qui commence par
    upd = Updater(parking, parkname)
    print(f"etat parking : {upd}")
    déterminait la durée de vie d'un objet (en gros comme en c#, par exemple)
    or la ce que j'ai constaté c'est que s'il n'y a aucune référence ca marche (destruction a la fin du bloc)
    mais si il y en a (alors que tous les objets sont déclarés dans ce même bloc et que théorique ils devraient etre détruit a la sortie de ce bloc) alors le ramassage miette agit qu'a la fin du soft

  6. #6
    Membre Expert
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 068
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 068

  7. #7
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 833
    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 833
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par ikeas Voir le message
    je pensais (sans doute naïvement) que tout ce qui était crée dans un bloc,
    déterminait la durée de vie d'un objet (en gros comme en c#, par exemple)
    Si c'était le cas, alors un algorithme de ce style...
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    for i in range(10):
    	if(test quelconque vrai)…:
    		trouve=True
    		break
    else:
    	trouve=False
     
    print(trouve)
    ... ne pourrait pas fonctionner.
    => portée et visibilité.
    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]

  8. #8
    Membre Expert
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 562
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 562
    Par défaut
    oui je comprends
    mais ce qui m'a étonné c'est que justement en sortant d'une fonction
    def xxx():
    x = MonObjet()
    ca détruit bien les objets qui ont été crée dedans.... sauf si y'a des references entre eux lol

  9. #9
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 062
    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 : 4 062
    Par défaut
    Bonsoir,

    En python on ne gère pas la libération de la mémoire, cela est géré par le garbage collector. Surcharger la méthode __del__ c'est prendre le risque de casser ce fonctionnement.
    Dans le cas où tu souhaites une forme de sauvegarde automatique avant suppression, on peut utiliser comme tu le fais une méthode intermédiaire.

Discussions similaires

  1. Réponses: 4
    Dernier message: 04/09/2008, 17h59
  2. [Conception] Rerchercher des informations sur une autre table
    Par tilou dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 07/05/2006, 19h35
  3. Formulaire avec liste basée sur une autre table
    Par sabotage dans le forum Langage SQL
    Réponses: 6
    Dernier message: 10/08/2005, 13h43
  4. pb d'insertion avec un SELECT sur une autre table
    Par epeichette dans le forum Requêtes
    Réponses: 3
    Dernier message: 03/01/2005, 22h58
  5. pb avec des clés sur un formulaire
    Par marie253 dans le forum Bases de données
    Réponses: 7
    Dernier message: 17/06/2004, 13h53

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