The joys of weakrefs... references to instance methods (callbacks)
Mike C. Fletcher
mcfletch at geocities.com
Sat Feb 9 06:56:49 EST 2002
Sat down to work out a model-view framework for a little application and
had one of those "oh, darn, didn't think that out very carefully"
moments. You see, I was planning on doing a fairly straightforward
callback-passing mechanism:
WatchAble.addWatcher( callback )
With callback getting a nicely formatted call, giving both the object
and an event object from which it could extract all kind of nice "what
type of event" occured information.
Now, of course, being a good little boy (evidence to the contrary), I
was going to use weakref.ref objects to hold the callbacks, so that when
the view objects are destroyed, their callbacks will no longer get
called (since that causes Nasties(TM)).
It's a strange thing, but the most convenient callback is almost allways
a bound method of a view object:
myModelObject.addWatcher( myViewObject.OnModelUpdated )
myViewObject.OnModelUpdated is a _new_ Python object (a bound method),
with only the reference in the calling stack keeping it alive. The
weakref.ref( Which is, of course, where everything goes straight south
in a handbasket. myViewObject.OnModelUpdated is actually a new Python
objectmyViewObject.OnModelUpdated ) call (in addWatcher) will generate
the reference object. That reference immediately goes to "dead" status
as the line of code after addWatcher is executed.
Well, there's an obvious solution, I can create an explicit callback
object, store it instead of the weakref, and let it do the
de-referencing to get the method (as long as the instance and function
are both still available). Basically, I need to wrap weakref.ref like so:
import weakref, types, new
class MethodRef:
"""Weak-reference to a method that takes the component parts of the
object, rather than the object itself for the "live" definition"""
def __init__( self, object ):
self.instance = weakref.ref( object.im_self )
self.function = weakref.ref( object.im_func )
def __call__( self ):
instance = self.instance()
function = self.function()
if instance and function:
return new.instancemethod( function, instance,
instance.__class__ )
else:
return None
def ref( object ):
if type(object) == types.MethodType:
return MethodRef( object )
else:
return weakref.ref( object )
Yes, it's slightly different semantics than weakref, but it's actually
useful in the real world ;) . Anyway, thought I'd share the code so
that people can object that it's a tool of the devil :) . If the powers
that be want to point out any reasons why I shouldn't do this, would
love to hear it before my house of cards goes *phoosh*.
Enjoy all,
Mike
_______________________________________
Mike C. Fletcher
http://members.rogers.com/mcfletch/
More information about the Python-list
mailing list