[Python-3000] weakrefs of bound methods

Nick Craig-Wood nick at craig-wood.com
Sun Feb 17 10:29:56 CET 2008


On Fri, Feb 15, 2008 at 01:20:03PM -0800, Guido van Rossum wrote:
> But maybe given how rare the use case is, it would be easier to just
> create a custom class in weakref.py that does what Nick requested.

I still don't like the silent failure, but a noisy failure and a
custom class would be great.

FYI here is the class I was writing which tripped me up.  I created
this to untangle some spaghetti code in a reasonably complex GUI
application I'm writing.

Instead of there being lots of hardcoded callbacks in the GUI objects
I made a central registry which made the code a lot cleaner.  The
weakrefs avoided registration and deregistration.

Since this is used from GUI code all the callback functions I needed
to add are bound methods.

(The last time I got tripped by this was a similar case involving 3rd
parties registering interests in other classes changing.)

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

class Callback(object):
    """
    A holder for functions which need to be called back at some specific point

    Silently fails if you pass in bound methods!
    """
    def __init__(self):
        self.fns = WeakKeyDictionary()
    def add(self, fn):
        """Add function to be called later."""
        self.fns[fn] = True
    def call(self):
        """Call all the registered functions"""
        for fn in self.fns.keys():
            fn()

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

Here is my explicit (no introspection) work-around - there are
obviously better solutions!

class Callback(object):
    """
    A holder for functions which need to be called back at some specific point
    """
    def __init__(self):
        self.fns = WeakKeyDictionary()
    def add(self, fn, attribute=None):
        """
        Add function to be called later.  Either pass in a function,
        or an object and an attribute to call.  Don't pass in bound
        methods since you can't take a weakref of a bound method. It
        holds weakrefs so doesn't need to be deregistered.
        """
        self.fns[fn] = attribute
    def call(self):
        """Call all the registered functions"""
        for fn, attribute in self.fns.iteritems():
            if attribute is not None:
                fn = getattr(fn, attribute)
            fn()


-- 
Nick Craig-Wood <nick at craig-wood.com> -- http://www.craig-wood.com/nick


More information about the Python-3000 mailing list