6
votes

del myClass n'appelle pas objet .__ del __ ()

J'ai une classe qui ouvre un fichier pour écrire. Dans mon destructeur, j'appelle la fonction qui ferme le fichier: xxx

mais lorsque je supprime l'objet avec le code comme: xxx

si J'essaie de réintégrer l'objet, j'obtiens une erreur de valeur: xxx

alors que si j'appelle myobj.close () avant del myobj Je ne reçois pas ce problème. Alors pourquoi n'est-il pas __ del __ () être appelé?


4 commentaires

Essayez d'hériter de objet - ne le faisant pas a été considéré comme un style obsolète depuis six ans.


Vous devriez montrer un autre code. Comment peut-on vous dire comment myobj.close () change de choses, sans savoir ce qu'il fait?


N'oubliez pas que del n'appelle pas __ del __ . Cela supprime l'une des références. Généralement, il est préférable de fermer explicitement, éventuellement à l'aide du protocole de Contexte Manager ( avec la déclaration ).


@Marcin - qui résolva-t-on ... post comme une réponse? Toujours curieux de savoir pourquoi cela devrait être le cas ...


4 Réponses :


8
votes

Ce n'est pas ce que del fait. Il est malheureux que __ del __ a le même nom que del , car ils ne sont pas liés les uns aux autres. Dans la terminologie moderne, la méthode __ del __ serait appelée un finaliseur , pas un destructeur et la différence est importante.

La différence courte est qu'il est facile de garantir quand un destructeur est appelé, mais vous avez très peu de garanties sur lorsque __ del __ sera appelé et il pourrait jamais être appelé . Il existe de nombreuses circonstances différentes pouvant causer cela.

Si vous voulez un scopage lexical, utilisez un avec la relève . Sinon, appelez myobj.close () directement. La déclaration del ne supprime que des références, pas des objets.

J'ai trouvé une autre réponse ( lien ) à une question différente qui répond à cela plus en détail. Il est regrettable que la réponse acceptée à cette question contienne des erreurs flagrantes.

edit: Comme notitors noté, vous devez hériter de objet . C'est bon, mais il est toujours possible que __ del __ ne soit jamais appelé (vous pourriez avoir de la chance). Voir la réponse liée ci-dessus.


0 commentaires

8
votes

Êtes-vous sûr de vouloir utiliser __ del __ code>? Il y a Problèmes avec __ del __ code> et collection de déchets .

Vous pouvez faire myClass a Contexte Manager à la place: P >

with MyClass() as myobj:
    ...


3 commentaires

+1 pour mentionner les problèmes. docs.python.org/library/gc.html#gc.grage dit que «des objets qui ont __del __ __ () et font partie d'un cycle de référence car l'ensemble du cycle de référence doit être irréelectable, y compris des objets non nécessairement dans le cycle mais ne sont pas atteints de celui-ci.»


Je ne vois pas comment il y a un cycle de référence dans l'exemple de l'OP. Il y a un objet, il obtient del d, et __ del __ () ne s'appelle pas.


De plus, dans ma situation, je préférerais laisser la GC gérer des choses car il n'a pas besoin de se fermer immédiatement, mais cela a finalement ... mais cela a toujours des problèmes. Et non, les gestionnaires de contexte ne sont pas une vraie solution. Ils vous limitent à la fermeture de l'objet dans la même fonction appeler et d'indenter votre code un niveau à chaque fois que vous en utilisez un. Rend ça illisible quand je veux créer 20 d'entre eux.



2
votes

Votre code doit hériter de objet - ne le faisant pas a été considéré par date (sauf dans des cas particuliers) pendant au moins six ans.

Vous pouvez lire sur __ del __ ici: http: //docs.pytthon.org/reference/datamodel.html#Object. del

La version courte de la raison pour laquelle vous devez hériter de objet est que __ del __ est uniquement "magique" sur des classes de style neuf.

Si vous devez compter sur l'appel d'un finaliseur, je suggère fortement que vous utilisiez l'approche du gestionnaire de contexte recommandée dans d'autres réponses, car c'est une solution portable et robuste.


2 commentaires

Ah vient de trouver une instance où cette "magie" ne fonctionne pas ... en utilisant ipython à la place.


@TDC: À moins que je me trompe, Ipython est basé sur CPPHON. Dans tous les cas, si vous comptez sur le comportement d'une instance particulière, votre code sera non portable. Il serait probablement préférable d'utiliser l'approche du gestionnaire de contexte recommandée dans d'autres réponses.



0
votes

Peut-être que quelque chose d'autre se réfère, c'est pourquoi __ del __ code> n'est pas appelé (encore).

Considérez ce code: P>

#!/usr/bin/env python

import time

class NiceClass():
    def __init__(self, num):
        print "Make %i" % num
        self.num = num
    def __del__(self):
        print "Unmake %i" % self.num

x = NiceClass(1)
y = NiceClass(2)
z = NiceClass(3)
lst = [x, y, z]
time.sleep(1)
del x
del y
del z
time.sleep(1)
print "Deleting the list."
del lst
time.sleep(1)


1 commentaires

Il n'y avait certainement qu'une seule référence dans ce cas