__del__ never called

I'm using wxPython 2.4.0.1 under Linux.
I've written a simple app that builds a custom wxPanel; when the user clicks a
button, the panel is destroyed.
Here is the source:

----- Test.py -----
from wxPython.wx import *

class App(wxApp):
  def OnInit(self):
    wnd = MainWnd(None)
    self.SetTopWindow(wnd)
    return 1

class MainWnd(wxFrame):
  def __init__(self, parent):
    wxFrame.__init__(self, parent, -1, "Title")
    b = wxButton(self, 1, "Destroy")
    self.v = TestViewer(self)
    
    EVT_BUTTON(self, 1, self.doDestroy)
    self.Show(1)
  
  def doDestroy(self, event):
    self.v.Destroy()
    del self.v

class TestViewer(wxPanel):
  def __init__(self, parent):
    wxPanel.__init__(self, parent, -1)
  
  def __del__(self):
    print "TestViewer destructor"

app = App(0)
app.MainLoop()

···

------------------

My problem is that TestViewer.__del__ method is never called. Does this mean
that TestViewer instance isn't freed (please note that I explicitly call
Destroy() and del() on it)?

Thanks for any help.

--
  Anakim Border
  aborder@tin.it

Anakim Border wrote:

I'm using wxPython 2.4.0.1 under Linux.
I've written a simple app that builds a custom wxPanel; when the user clicks a button, the panel is destroyed.
Here is the source:

[...]

My problem is that TestViewer.__del__ method is never called. Does this mean that TestViewer instance isn't freed (please note that I explicitly call Destroy() and del() on it)?

To be honest I don't know why it isn't being called. I'll trace through the code again but it appears to me that the reference count is properly decremented. You can check this with sys.getrefcount:

     def doDestroy(self, event):
         print sys.getrefcount(self.v) - 1
         self.v.Destroy()
         print sys.getrefcount(self.v) - 1
         del self.v

The -1's are there because getrefcount will normally report an extra reference due to the reference added for the function call. The above prints 2 and then 1 when run, so the only reference left is self.v, and then you delete that.

Oh, wait a sec, I just realized what is happening. The Dead Object modifications I made a while back (see CHANGES.txt) are getting involved here and are throwing us both off the track. When the C++ object is deleted it replaces the class of the Python instance with a reference to the _wxPyDeadObject class, which, of course, has no __del__ method and certainly knows absolutly nothing about your __del__ method, so it is never called when the instance finally is deleted. You can see this if you add "print self.v.__del__" after the Destroy.

I'll have to think about this a bit to see if there is a way to preserve the __del__ of the original class. Or maybe it should just be called explicitly before the classes are switched. Anybody have any thoughts on this?

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Oh, wait a sec, I just realized what is happening. The Dead Object
modifications I made a while back (see CHANGES.txt) are getting involved
here and are throwing us both off the track. When the C++ object is

That's correct. I modified the code slightly:

...
    import gc
    self.v.Destroy()
    print gc.get_referrers(self.v)
...

and the output was:

[{'this': '_846c6f0_wxFrame_p', 'thisown': 1, 'v': wxPython wrapper for
DELETED TestViewer object! (The C++ object no longer exists.)}]

···

--
  Anakim Border
  aborder@tin.it