views:

2404

answers:

3

In Python, is there a way to bind an unbound method without calling it?

I am writing a wxPython program, and for a certain class I decided it'd be nice to group the data of all of my buttons together as a class-level list of tuples, like so:

class MyWidget(wx.Window):
    buttons = [("OK", OnOK),
               ("Cancel", OnCancel)]

    # ...

    def Setup(self):
        for text, handler in MyWidget.buttons:

            # This following line is the problem line.
            b = wx.Button(parent, label=text).Bind(wx.EVT_BUTTON, handler)

The problem is, since all of the values of handler are unbound methods, my program explodes in a spectacular blaze and I weep.

I was looking around online for a solution to what seems like should be a relatively straightforward, solvable problem. Unfortunately I couldn't find anything. Right now, I'm using functools.partial to work around this, but does anyone know if there's a clean-feeling, healthy, Pythonic way to bind an unbound method to an instance and continue passing it around without calling it?

A: 

This will bind self to handler:

bound_handler = lambda *args, **kwargs: handler(self, *args, **kwargs)

This works by passing self as the first argument to the function. object.function() is just syntactic sugar for function(object).

Yes, but this calls the method. The problem is I need to be able to pass the bound method as a callable object. I have the unbound method and the instance I'd like it to be bound to, but can't figure out how to put it all together without immediately calling it
leo-the-manic
No it doesn't, it'll only call the method if you do bound_handler(). Defining a lambda does not call the lambda.
+12  A: 

This can be done cleanly with types.MethodType. Example:

import types

def f(self): print self

class C(object): pass

meth = types.MethodType(f, C(), C) # Bind f to an instance of C
print meth # prints <bound method C.f of <__main__.C object at 0x01255E90>>
Kiv
+11  A: 

All functions are also descriptors, so you can bind them by calling their __get__ method:

bound_handler = handler.__get__(self, MyWidget)

Here's R. Hettinger's excellent guide to descriptors.

Alex Martelli
That's pretty cool. I like how you can omit the type and get back a "bound method ?.f" instead.
Kiv