The woes of event handling in wxPython

Jp Calderone exarkun at intarweb.us
Fri Apr 25 19:08:34 EDT 2003


On Fri, Apr 25, 2003 at 09:43:20PM +0000, sparky wrote:
> [snip]
> 
> Using the evtmgr interface to deal with cleaning up the old dead objects 
> created by sending dialogs to the great bit bucket in the sky doesn't 
> seem to work.
> 
> Here is some example code (sorry I cannot give you a complete class, 
> they asked us not to post any code):
> 
> import pubsub, evtmgr
> class EditMemberDialog(EditDialog):
>     def __init__(self, parent, *args):
> .
> .
> <snip a bunch of stuff that works>
> .
> .
> .
> 	eventManager.Register(self.__saveMemberGoals, EVT_TEXT,
> 			      self.descriptionText)
>         server.subscribe(topic    = CommandPattern.CommandHistory,
>                          listener = self.__notifyObjectOfChange)
> 
> <snip a bunch of stuff that works>
> 
>     def __del__(self):
> 
> 	eventManager.Deregister(self.__saveMemberGoals)
> 	server.unsubscribe(self.__notifyObjectOfChange)
> 	self.parent.__del__()
> 
> 
> 
> So, now when I launch the dialog the first time. It works just fine.
> The second time it gets launched I get the:
> 
> wxPython.wx.wxPyDeadObjectError: The C++ part of the EditMemberDialog 
> object has been deleted, attribute access no longer allowed.
> 
> What am I missing?

  If EditMemberDialog instances have a reference to their parent, and their
parent has a reference to them, then what you have is a cycle.  A cycle
become uncollectable if more than one object in it implements __del__.

  Furthermore, when you pass self.__notifyObjectOfChange to
server.subscribe(), you are giving server (or whever eventually holds on to
the reference given by the listener parameter) a reference to self.  This
will probably preclude cleanup of the object entirely.

  Explicit unsubscription seems like the only course.  There are a few
tricks to doing this that might be of interest.  One involves keeping
WeakRefs to objects and calling the unsubscription function when the WeakRef
is no longer valid (it doesn't seem like this will work, because of the
reference I mentioned in the previous paragraph).  Another approach is to
subscribe before a "try:" block and unsubscribe in the matching "finally:"
block.  I'm not sure if this is feasible for use in a GUI app where you lose
control of execution between the subscription and the unsubscription.

  The last, and least magical, approach I can think of is to explicitly call
the unsubscribe method when you are finished with the object, and then clean
up the references to that object so it will be freed.  This probably won't
be easy, since much of the code is already written, but it may be the only
solution.

  Hope this helps,

  Jp

-- 
http://catandgirl.com/view.cgi?90
-- 
 up 36 days, 19:03, 9 users, load average: 0.48, 0.42, 0.37





More information about the Python-list mailing list