__del__ doesn't work

Graham Dumpleton grahamd at dscpl.com.au
Mon Feb 16 22:51:55 CET 2004


Josiah Carlson <jcarlson at nospam.uci.edu> wrote in message news:<c0pmq5$dm1$1 at news.service.uci.edu>...
> > I don't believe that Python can cope with this and the object
> > will never actually be deleted. Please correct me if I am wrong.
> 
> You are incorrect.
> 
>  From http://www.python.org/doc/current/lib/module-gc.html:
> "The gc module is only available if the interpreter was built with the 
> optional cyclic garbage detector (enabled by default). If this was not 
> enabled, an ImportError is raised by attempts to import this module."
>
> ...

Hmmm, that isn't quite how I read it. If objects in a cycle have
__del__
methods, you have to break the cycles somehow still. See:

  garbage

    A list of objects which the collector found to be unreachable but
could not
    be freed (uncollectable objects). By default, this list contains
only objects
    with __del__() methods. Objects that have __del__() methods and
are part
    of a reference cycle cause the entire reference cycle to be
uncollectable,
    including objects not necessarily in the cycle but reachable only
from it.
    Python doesn't collect such cycles automatically because, in
general, it isn't
    possible for Python to guess a safe order in which to run
the__del__() methods.
    If you know a safe order, you can force the issue by examining the
garbage list,
    and explicitly breaking cycles due to your objects within the
list. Note that these
    objects are kept alive even so by virtue of being in the garbage
list, so they
    should be removed from garbage too. For example, after breaking
cycles, do
    del gc.garbage[:] to empty the list. It's generally better to
avoid the issue by
    not creating cycles containing objects with __del__() methods, and
garbage
    can be examined in that case to verify that no such cycles are
being created.

> > In certain circumstances where I have had this problem and I
> > needed to know the object would be destroyed as soon as
> > possible, I have had to add a method to the class which could
> > be called to undo any references the class held which pointed
> > back onto itself.
>
> That is smart, but it does beg the question: Why would a class instance 
> need to have a reference to itself?  I can understand certain reasons, 
> but many can be translated into weakrefs with little difficulty.

Because the Python class was a wrapper around a C++ class which
provided callbacks from an event system. In the Python wrapper, one
specified in the code dynamically what method of the Python class
you wanted the event delivered to. Thus, the Python class has a
reference back not to the class, but a method of the class. This has
the same effect of creating a loop. Ie.,

class A:

  def __init__(self):
    print "init"
    self.a = self._a

  def __del__(self):
    print "del"

  def _a(self):
    pass

a = A()
del a

Will print "init" only.

Or for an actual example:

import netsvc

class Handler(netsvc.Agent):

  def __init__(self):
    netsvc.Agent.__init__(self)
    print "init"
    self.startTimer(self.timeout,30)

  def __del__(self):
    print "del"

  def timeout(self):
    print "timeout"

o = Handler();
del o

netsvc.Dispatcher().run()

If an attempt was made to delete the Handler object before the timer
expired, it wouldn't. Instead it would hang around until the timer
expired, which isn't what was wanted. Thus need to do:

o.Handler()
o.destroyAgent()
del o

Where the destroyAgent() method undoes any cycles caused by the
registered callbacks.

> > I have looked at weak references, but have not been satisfied
> > that it could be used in the situation where I had to overcome the
> > problem.
> 
> Weak referenced objects are not required to be deleted immediately 
> following the final strong reference removal.  Perhaps that is where 
> your confusion lies.
> 
> Nowhere does it claim to delete immediately following the final strong 
> reference removal, the garbage collector collects when it is ready to. 
> One thing to remember is that sometimes references hide.

That things aren't deleted immediately is why I wasn't satsified that
it
could be used in my situation. I needed the immediate deletion that
would normally occur in CPython when a final reference was deleted.
Without it, the wrapped C++ class wouldn't get destroyed and the
registrations it had made on behalf of the Python wrapper to events
generated by the event system wouldn't be removed. Thus per example
above, even though you had deleted the local reference to the object,
the object was still active and still receiving events. If the handler
did
some sort of permanent event registration against some aspect of the
event system, it would never die.



More information about the Python-list mailing list