2009-07-10 9 views
7

J'ai réfléchi à la façon dont j'écris des classes en Python. Plus précisément comment le constructeur est implémenté et comment l'objet doit être détruit. Je ne veux pas me fier au comptage de références de CPython pour faire le nettoyage d'objet. Cela me dit essentiellement que je devrais utiliser des instructions pour gérer les durées de vie de mes objets et que j'ai besoin d'une méthode close/disposition explicite (cette méthode pourrait être appelée depuis __exit__ si l'objet est également un gestionnaire de contexte).Est-ce que c'est vraiment OK de fermer/jeter des objets dans __del__?

class Foo(object): 
    def __init__(self): 
     pass 
    def close(self): 
     pass 

Maintenant, si tous mes objets se comportent de cette manière et tout mon code utilise des déclarations ou des appels explicites à close() (ou dispose()) Je ne vois pas vraiment la nécessité pour moi de mettre un code dans __del__. Devrions-nous vraiment utiliser __del__ pour disposer de nos objets?

+2

Je ne veux pas me fier au comptage de références de CPython pour effectuer le nettoyage d'objet. Pourquoi pas sur terre? Quel est le problème avec le comptage des références d'objets? –

+0

@ S.Lott, le comptage de référence n'est pas là si vous déplacez votre code vers un environnement avec une récupération de place plus avancée, comme Jython ou IronPython - et si un jour CPython (par exemple via Unladen Swallow) est traîné en criant dans le 21ème siècle, aussi? Je suis d'accord avec le PO sur le fait de ne pas compter sur RC dans mes bibliothèques portatives et réutilisables (par opposition aux modules à usage unique, jetables, scripts et mineures). –

+0

@ S.Lott: Alex a déjà répondu à votre question. Une autre bonne raison de vouloir ne pas compter sur le comptage des références est l'ECE issue du projet PyPy. Les personnes derrière elle semblent être optimistes quant à sa capacité à fournir des accélérations substantielles par rapport à CPython. – Arlaharen

Répondre

13

Réponse courte: Non

réponse longue: Utiliser __del__ est difficile, principalement parce qu'il est pas garanti d'être appelé. Cela signifie que vous ne pouvez pas faire des choses qui doivent absolument être faites. Cela signifie que __del__ peut seulement être utilisé pour les nettoyages qui arriveraient plus tôt ou plus tard, comme nettoyer les ressources qui seraient nettoyées quand le processus se termine, donc cela n'a pas d'importance si __del__ n'est pas appelé. Bien sûr, ce sont généralement les mêmes choses que Python fera pour vous. Donc, cela rend __del__ inutile.

De même, __del__ est appelée lorsque Garbage Garbage est collecté, et vous ne souhaitiez pas attendre la collecte de Python, ce qui signifie que vous ne pouvez pas utiliser __del__ de toute façon. Par conséquent, n'utilisez pas le __del__. Utilisez __enter__/__exit__ à la place.

Pour votre information: Voici un exemple d'une situation de non-circulaire où l'destructor ne s'appelle:

class A(object): 
    def __init__(self): 
     print('Constructing A') 

    def __del__(self): 
     print('Destructing A') 

class B(object): 
    a = A() 

OK, donc il est un attribut de classe. Évidemment c'est un cas spécial. Mais cela montre simplement que se faire __del__ n'est pas simple. Je suis assez sûr que j'ai vu plus de situations non-circulaires où __del__ n'est pas appelé.

+0

J'ai posé une question similaire il y a un an. Jusqu'à présent, personne n'a été capable de nommer un scénario légitime dans lequel la méthode '__del__' serait utile. En ce qui me concerne, la méthode n'aurait jamais dû être en Python en premier lieu. C'est bon pour rien et donne aux gens la fausse impression qu'ils pourraient l'utiliser pour le nettoyage. – antred

8

Pas nécessairement. Vous rencontrerez des problèmes lorsque vous avez des références cycliques. Eli Bendersky fait un bon travail d'expliquer cela dans son blog:

+0

+1 très bon lien – dfa

+1

Malheureusement, l'article lié tire une conclusion fausse. '__del__' n'est pas garanti d'être appelé. Du tout. Ce n'est pas seulement pour les références cycliques. En outre, il dit ** "Les références cycliques, cependant, sont souvent un signe de mauvaise conception" ** WTF? – nosklo

0

Si vous êtes sûr que vous ne rentrerai pas dans les références cycliques, puis en utilisant __del__ de cette façon est OK: dès Lorsque le compteur de référence atteint zéro, la machine virtuelle CPython appelle cette méthode et détruit l'objet.

Si vous envisagez d'utiliser des références cycliques - pensez-y très sérieusement et vérifiez si des références faibles peuvent vous aider; Dans de nombreux cas, les références cycliques sont un premier symptôme de mauvaise conception.

Si vous n'avez aucun contrôle sur la façon dont votre objet va être utilisé, l'utilisation de __del__ peut ne pas être sûre.

Si vous envisagez d'utiliser JPython ou IronPython, __del__ n'est pas fiable du tout, car la destruction de l'objet final se produira au garbage collection, et c'est quelque chose que vous ne pouvez pas contrôler. En résumé, à mon avis, __del__ est généralement parfaitement sûr et bon; Toutefois, dans de nombreux cas, il pourrait être préférable de prendre du recul et d'essayer d'envisager le problème d'un point de vue différent. un bon usage de try/except et de contextes peut être une solution plus pythonique.

Questions connexes