Question

Je suis nouveau python et travaille à travers les exemples dans « un octet de Python » Swaroop CH de. Je vois un comportement avec la méthode __del__ qui me laisse perplexe.

En fait, si je lance le script suivant (en Python 2.6.2)

class Person4:
    '''Represents a person'''
    population = 0

    def __init__(self, name):
        '''Initialize the person's data'''
        self.name = name
        print 'Initializing %s'% self.name

        #When the person is created they increase the population
        Person4.population += 1

    def __del__(self):
        '''I am dying'''
        print '%s says bye' % self.name

        Person4.population -= 1

        if Person4.population == 0:
            print 'I am the last one'
        else:
            print 'There are still %d left' % Person4.population


swaroop = Person4('Swaroop')
kaleem = Person4('Kalem')

l'aide de la console de python (ou la console interactive Spyder) Je vois ce qui suit:

  
    
      

execfile (u'C: \ 1_eric \ Python \ test1.py ')
      Swaroop
Initialisation       Kalem Initializing

             

execfile (u'C: \ 1_eric \ Python \ test1.py ')
      Swaroop
Initialisation       Swaroop dit au revoir
      Je suis le dernier
      Kalem
Initialisation       Kalem dit au revoir
      Je suis le dernier

    
  

Pourquoi la méthode __del__ étant appelée immédiatement après la __init__ la deuxième manche?
Je suppose que, puisque les mêmes noms d'instance ( « de Swaroop » et « Kaleem ») sont utilisés que publie l'instance d'origine et la collecte des ordures il. Mais, cela semble jouer des ravages avec le nombre actuel de la population.

Qu'est-ce qui se passe ici?
Qu'est-ce qu'un bon moyen d'éviter ce genre de confusion?
   Évitez l'utilisation de __del__?    Vérifiez les noms d'instance existants avant de les réutiliser?    ...

Merci, Eric

Était-ce utile?

La solution

Conseils généraux: ne pas utiliser __ __ del en Python. Il peut briser la collecte des ordures dans un certain nombre de façons, esp. dans le cas des références circulaires entre les objets.

Dans votre exemple, il sont diverses questions liées à l'utilisation de execfile () - qui n'est pas une meilleure pratique - et la redéfinition des variables globales. Soit dit en passant, si vous avez vraiment besoin de créer un pseudo-destructor (par exemple un code qui est invoqué chaque fois que l'objet se ramasse-miettes), écrire une soi-disant fonction « finaliseur » (ce n'est pas correctement une destructor) et appeler à l'aide weakref rappel .ref. Il ne devrait pas être une méthode d'instance bien sûr, et rappelez-vous que lambda crée en fait une fermeture, être donc sûr de ne pas fuir toute référence à l'auto dans le rappel! Si vous avez besoin des données de l'instance détruite, utilisez l'approche de l'argument par défaut Func, juste être sûr jamais pour faire référence à « moi » à l'intérieur du lambda, sinon cela ne fonctionnera pas.

from weakref import ref
from time import sleep

class Person4:
    '''Represents a person'''
    population = 0

    def __init__(self, name):
        '''Initialize the person's data'''
        self.name = name
        print 'Initializing %s'% self.name

        #When the person is created they increase the population
        Person4.population += 1

        self._wr = ref(self, lambda wr, name=self.name: Person4_finalizer(name))

def Person4_finalizer(name):
        '''I am dying'''
        print '%s says bye' % name

        Person4.population -= 1

        if Person4.population == 0:
            print 'I am the last one'
        else:
            print 'There are still %d left' % Person4.population

p1 = Person4("one")
p2 = Person4("two")
p3 = Person4("three")

del p2
del p3
sleep(5)

sortie (le sommeil est là pour vous aider à voir ce qui se passe):

Initializing one
Initializing two
Initializing three
two says bye
There are still 2 left
three says bye
There are still 1 left
one says bye
I am the last one

Autres conseils

Il y a deux choses qui se passent ici. Lorsque votre classe Person4 est instancié, il initialise sa variable de classe population à 0. À partir de votre console interactive, vous semblez être en cours d'exécution le fichier « test1.py » plusieurs fois. La deuxième fois que vous l'exécutez, la classe Person4 est déclarée à nouveau ce qui le rend techniquement différents de la première (même si elle a le même nom). Cela signifie qu'il a son propre compte de population indépendant.

Maintenant, swaroop et kaleem sont global variables partagées entre les deux instances du "test1.py". Python utilise en interne comptage de référence pour la plupart de sa collecte des ordures automatique, de sorte que l'instance d'origine de la première classe Person4 n'est pas libéré jusqu'à ce que la seconde affectation à swaroop. Attribution de swaroop décrémente le compte de référence pour la première instance, ce qui __del__ être appelé parce que le compte de référence est maintenant zéro. Mais parce que vous faites référence à Person4 par nom à l'intérieur __del__(), lorsque le précédent par exemple disparait décrémente nouveau nombre Person4.population, au lieu de l'ancien comte de population Person4.

Il faut espérer que du sens. Je ne vois pas pourquoi cela pourrait être source de confusion pour quelqu'un d'apprendre Python. Votre utilisation de variables de classe en même temps que la redéfinition de la classe Person4 à l'aide execfile() est d'autres questions déroutantes. Pour ce que ça vaut, j'ai écrit beaucoup de code Python et je ne pense pas que j'ai jamais eu besoin d'utiliser la méthode spéciale __del__.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top