views:

139

answers:

4

i am trying to store some method callbacks but referring to it will keep the bound object alive, so i tried to keep a weakref to method but that doesn't seems to be possible?

so

  • Why can't i keep a weak ref. to method (see example below)

  • What is the best way to keep method ref? any thing in standard lib? Or I will have to keep function and object ref. separate?

example:

import weakref

class A(object):
    def m(self): pass

a = A()

import weakref

class A(object):
    def m(self): pass

a = A()

rm = weakref.ref(a.m)
print "is weak ref to method dead?",rm() is None
print "Q1. why can't i keep weakref to bound method?"

ra = weakref.ref(a)
m = a.m
print "delete object"
del a
print "is object dead?",ra() is None
print "delete method"
del m
print "is object dead?",ra() is None
print "Q2. hmmm so i am stuck i can't keep a ref as it stops the object from gc, but weakref to method isn't working?"
+3  A: 

Since the method is bound to the object, what would you expect to do with it if the object doesnt exist? What would self contain?

If you dont need the object in the method, make it a classmethod. Then your object will be GC:d even if you have a normal reference to the method.

truppo
but in this case object does exist, in the example I do not delete object till end
Anurag Uniyal
and I do want object, my simple way question is "is there a way to keep callbacks around , as weakref for objects, something like that
Anurag Uniyal
A: 

I have asked the same question here! In my question, I talk about GObject, but recognize it is a general problem in any kind of Python! I got help by lioro there, and what I use in my current code is below. Some important points:

  • You can't weakref the method object. You have to weakref the instance and its function attribute, or simply the method name (as I do in my code below)

  • You can add some mechanism to unregister the callback when your connected object goes away, if you don't do this, you will have the WeakCallback object live on instead, and exectute an empty method when the even occurs.

.

class WeakCallback (object):
    """A Weak Callback object that will keep a reference to
    the connecting object with weakref semantics.

    This allows object A to pass a callback method to object S,
    without object S keeping A alive.
    """
    def __init__(self, mcallback):
        """Create a new Weak Callback calling the method @mcallback"""
        obj = mcallback.im_self
        attr = mcallback.im_func.__name__
        self.wref = weakref.ref(obj, self.object_deleted)
        self.callback_attr = attr
        self.token = None

    def __call__(self, *args, **kwargs):
        obj = self.wref()
        if obj:
            attr = getattr(obj, self.callback_attr)
            attr(*args, **kwargs)
        else:
            self.default_callback(*args, **kwargs)

    def default_callback(self, *args, **kwargs):
        """Called instead of callback when expired"""
        pass

    def object_deleted(self, wref):
        """Called when callback expires"""
        pass

Usage notes:

# illustration how I typically use it
weak_call = WeakCallback(self._something_changed)
long_lived_object.connect("on_change", weak_call)

I use the WeakCallback.token attribute in subclasses I've made to manage disconnecting the callback when the connecter goes away

kaizer.se
many other have pointer to similar solution, but I selected this one for being inpage
Anurag Uniyal
A: 

They have a nice solution in:

http://code.activestate.com/recipes/81253/

Take a look at the last example, posted by Anonymous.

Bruno Oliveira
+2  A: 

Recipe 6.10 in Python Cookbook, "Keeping References to Bound Methods Without Inhibiting Garbage Collection", offers a pretty thorough though concise discussion and solutions. You can read it online (on Google Books) here; we give credit for that recipe to Knapka, Jolliton and Nicodemus (partly from the original activestate cookbook recipe that another answer already mentioned) though of course, as usual in the Cookbook, we (me, my wife Anna, and David Ascher) are the ones responsible for the overall flow of discussion and the exact code version chosen for printing, so, if something's wrong with those, it's our fault;-).

Alex Martelli
+1 for you answering :), btw why weakref.ref doesn't work for bound method?
Anurag Uniyal
@Anurag, it works as intended: it makes the reference to the bound method object weak! So, since there's no *strong* reference to that bound method object, said object immediately goes "poof" -- just as the discussion I already pointed to explains.
Alex Martelli