Is overriding __del__() the best choice here?

Dan Oberlam picture Dan Oberlam · Feb 13, 2014 · Viewed 7.1k times · Source

I am trying to figure out the best way to remove something, preferably without having to write in a lot of code.

In my project I am simulating chemical compounds - I have Element instances bonded to other Element instances via a Bond instance. In chemistry bonds often break, and I'd like to have a clean way to do that. My current method is something like as follows

# aBond is some Bond instance
#
# all Element instances have a 'bondList' of all bonds they are part of
# they also have a method 'removeBond(someBond)' that removes a given bond 
# from that bondList
element1.removeBond(aBond)
element2.removeBond(aBond)
del aBond

I want to do something like

aBond.breakBond()

class Bond():
    def breakBond(self):
        self.start.removeBond(self) # refers to the first part of the Bond 
        self.end.removeBond(self) # refers to the second part of the Bond 
        del self

Alternately, something like this would be fine

del aBond

class Bond():
    def __del__(self):
        self.start.removeBond(self) # refers to the first part of the Bond 
        self.end.removeBond(self) # refers to the second part of the Bond 
        del self

Is any one of these ways of doing it preferable to the others, or is there some other way of doing this that I'm overlooking?

Answer

Bakuriu picture Bakuriu · Feb 13, 2014

Python uses garbage collection to manager memory, which means you do not have to delete anything. This class is fine:

class Bond():
    def breakBond(self):
        self.start.removeBond(self)
        self.end.removeBond(self)

note that del does not delete anything from memory! It simply removes a reference to an object, but objects can have more than one reference:

>>> some_list = [1,2,3]
>>> b = some_list
>>> del b   # destroys the list?
>>> b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'b' is not defined
>>> some_list   # list is still there!
[1, 2, 3]
>>> c = some_list
>>> del some_list
>>> c        # list is still there!
[1, 2, 3]
>>> del c

After the last del c the interpreter can deallocate the list. In CPython the deallocation will be done immediately (in this simple case), however in other implementation of the language the interpreter might not deallocate the list immediately.

Also note that __del__'s documentation cites this fact. Furthermore it is a really low-level method which you don't need 99.9% of the time, so it certainly isn't the right way to handle your situation.