Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force deletion of a python object?

I am curious about the details of __del__ in python, when and why it should be used and what it shouldn't be used for. I've learned the hard way that it is not really like what one would naively expected from a destructor, in that it is not the opposite of __new__ / __init__.

class Foo(object):      def __init__(self):         self.bar = None      def open(self):         if self.bar != 'open':             print 'opening the bar'             self.bar = 'open'      def close(self):         if self.bar != 'closed':             print 'closing the bar'             self.bar = 'close'      def __del__(self):         self.close()  if __name__ == '__main__':     foo = Foo()     foo.open()     del foo     import gc     gc.collect() 

I saw in the documentation that it is not guaranteed __del__() methods are called for objects that still exist when the interpreter exits.

  1. how can it be guaranteed that for any Foo instances existing when the interpreter exits, the bar is closed?
  2. in the code snippet above does the bar get closed on del foo or on gc.collect()... or neither? if you want finer control of those details (e.g. the bar should be closed when the object is unreferenced) what is the usual way to implement that?
  3. when __del__ is called is it guaranteed that __init__ has already been called? what about if the __init__ raised?
like image 405
wim Avatar asked Jul 21 '11 07:07

wim


People also ask

How do you completely delete an object in Python?

The del keyword in python is primarily used to delete objects in Python. Since everything in python represents an object in one way or another, The del keyword can also be used to delete a list, slice a list, delete a dictionaries, remove key-value pairs from a dictionary, delete variables, etc.

How do you destruct an object in Python?

A class implements the special method __del__(), called a destructor, that is invoked when the instance is about to be destroyed. This method might be used to clean up any non memory resources used by an instance.

What is __ del __ in Python?

The __del__() method is a known as a destructor method in Python. It is called when all references to the object have been deleted i.e when an object is garbage collected. Syntax of destructor declaration : def __del__(self): # body of destructor.


1 Answers

The way to close resources are context managers, aka the with statement:

class Foo(object):    def __init__(self):     self.bar = None    def __enter__(self):     if self.bar != 'open':       print 'opening the bar'       self.bar = 'open'     return self # this is bound to the `as` part    def close(self):     if self.bar != 'closed':       print 'closing the bar'       self.bar = 'close'    def __exit__(self, *err):     self.close()  if __name__ == '__main__':   with Foo() as foo:     print foo, foo.bar 

output:

opening the bar <__main__.Foo object at 0x17079d0> open closing the bar 

2) Python's objects get deleted when their reference count is 0. In your example the del foo removes the last reference so __del__ is called instantly. The GC has no part in this.

class Foo(object):      def __del__(self):         print "deling", self  if __name__ == '__main__':     import gc     gc.disable() # no gc     f = Foo()     print "before"     del f # f gets deleted right away     print "after" 

output:

before deling <__main__.Foo object at 0xc49690> after 

The gc has nothing to do with deleting your and most other objects. It's there to clean up when simple reference counting does not work, because of self-references or circular references:

class Foo(object):     def __init__(self, other=None):         # make a circular reference         self.link = other         if other is not None:             other.link = self      def __del__(self):         print "deling", self  if __name__ == '__main__':     import gc     gc.disable()        f = Foo(Foo())     print "before"     del f # nothing gets deleted here     print "after"     gc.collect()     print gc.garbage # The GC knows the two Foos are garbage, but won't delete                      # them because they have a __del__ method     print "after gc"     # break up the cycle and delete the reference from gc.garbage     del gc.garbage[0].link, gc.garbage[:]     print "done" 

output:

before after [<__main__.Foo object at 0x22ed8d0>, <__main__.Foo object at 0x22ed950>] after gc deling <__main__.Foo object at 0x22ed950> deling <__main__.Foo object at 0x22ed8d0> done 

3) Lets see:

class Foo(object):     def __init__(self):          raise Exception      def __del__(self):         print "deling", self  if __name__ == '__main__':     f = Foo() 

gives:

Traceback (most recent call last):   File "asd.py", line 10, in <module>     f = Foo()   File "asd.py", line 4, in __init__     raise Exception Exception deling <__main__.Foo object at 0xa3a910> 

Objects are created with __new__ then passed to __init__ as self. After a exception in __init__, the object will typically not have a name (ie the f = part isn't run) so their ref count is 0. This means that the object is deleted normally and __del__ is called.

like image 194
Jochen Ritzel Avatar answered Oct 09 '22 04:10

Jochen Ritzel