Python del on classes
Asked Answered
M

1

8

Lets assume we have a class in python:

class A(object):
    def __del__(self):
        print "Del!"

__del__ is called upon deleting/garbage collection of any A instance.

Is is possible to do the same for a class? I would like to have some method called when the class itself is garbage collected, which I assume is being done at the script exit.

Thanks in advance for any pointers!


Edit: Just as I have expected, everyone is trying to drive me away from using this technique (I would probably make such a comment myself:)), though the question still stands: is it possible?

I want to the the following: I have a class with a static member that needs to be cleaned.

class A(object):
    class Meta(type):
        def __new__(mcs, name, bases, attrs):
            attrs['conn'] = sqlite3.connect( DB_FILE )
            return type.__new__(mcs, name, bases, attrs)

    __metaclass__ = Meta

I would like A.conn.close() to be called, but just before the program closes - i.e. when I know that no more instances of A will be ever created. I know I can do this with atexit, but this just seems very ugly.

Mazur answered 9/4, 2011 at 21:10 Comment(13)
Using __del__ is already suspicious. It can make objects un-GC-able (in the presence of cycle, the GC doesn't know in which order they must be called since there are propably some dependencies) and since it's non-deterministic, cleanup is better put into a context manager. Why do you think you need this?Illegitimacy
You can make a factory class that has a __call__ method to create a new instance of desired class and __del__ method that does what you wantKenn
And anyway, I can't think of anything useful that can be made with this.Kenn
Never rely on gerbage collection for a particular set of behavior. The run time is at no obligation to ever collect anything, even at program termination. if you need cleanup, use a context manager.Larrylars
In garbage-collected environment, destructors are a bad thing. Avoid it. Or, rather, ask a question about the problem you're solving, not the small technicality. Probably this would bring real answers.Corollaceous
Thanks for all comments, I provided more info in my question.Mazur
@Mazur - your extra info confirms that this is the wrong approach. @TokenMacGuy is absolutely correct in that the cleanup may never even happen.Parrott
I know it is not very elegant approach. What better do you propose?Mazur
@Mazur - you could use one of several ORM libraries that do all of that stuff for you behind the scenes. SQLObject or SQLAlchemy spring to mind.Parrott
What I write is meant to be a simple ORM:-). Do you know how SQLObject or SQLAlchemy handles DB connections? (i.e. has them open all the time and when they are closed)Mazur
Couldn't you use atexit in Meta::__new__ and hide its "ugliness"?Laxity
I could (as I mentioned in my question:)) and even I do now. But I am looking for cleaner solution if possible.Mazur
@Mazur - ah, okay :) I would maybe look at the SQLObject source.Parrott
W
7

The problem is that classes contain circular references back to themselves - so when they are deleted they are not easily collected - thus the __del__ method odf the metaclass is not called.

I could trigger it being called using Pypy's Python implementation, but not using cpython - either 2.6 or 3.2. And even to trigger that, I had to manually invoke the garbage collector - The Python environment at program exit is known to be full of inconsitencies, and the chances of the __del__ method being called while enough internal information on the class would exist to allow a sae shut down would be very slim.

Here is my Pypy session where I did trigger the call to the class' __del__

 ~]$ pypy                                                                                       
Python 2.5.2 (78826, Nov 29 2010, 00:18:05)                                                                       
[PyPy 1.4.0] on linux2                                                                                            
Type "help", "copyright", "credits" or "license" for more information.                                            
And now for something completely different: ``sorry, I'll teach the cactus how                                    
to swim later''                                                                                                   
>>>> import gc
>>>> class Meta(type):         
....    def __del__(cls):                          
....       print ("Arghh!!")                                              
....                                                                      
>>>> class A(object):                                                                     
....   __metaclass__ = Meta                                                                                     
....                                                                                                                                                                                                                
>>>> del A                                                                                                        
>>>> gc.collect()                                                                                                 
Arghh!!                                                                                                           
0                                                                                                                 
>>>>

2022 - as of Python 3.11 a06, the __del__ method in the metaclass works in cPython, if one calls gc.collect() after deleting all references to the class, just like it happens with pypy on this example.

Woolery answered 10/4, 2011 at 3:59 Comment(1)
And now for something completely different: "sorry, I'll teach the cactus how to swim later" It made my day. Thank you.Bulley

© 2022 - 2024 — McMap. All rights reserved.