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?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
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.
As a self-contained example pulled from Keith’s comment:
def bind(instance, func, as_name=None):
"""
Bind the function *func* to *instance*, with either provided name *as_name*
or the existing name of *func*. The provided *func* should accept the
instance as the first argument, i.e. "self".
"""
if as_name is None:
as_name = func.__name__
bound_method = func.__get__(instance, instance.__class__)
setattr(instance, as_name, bound_method)
return bound_method
class Thing:
def __init__(self, val):
self.val = val
something = Thing(21)
def double(self):
return 2 * self.val
bind(something, double)
something.double() # returns 42
Method 2
This can be done cleanly with types.MethodType. Example:
import types
def f(self):
print(self)
class C:
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>>
Method 3
Creating a closure with self in it will not technically bind the function, but it is an alternative way of solving the same (or very similar) underlying problem. Here’s a trivial example:
self.method = (lambda self: lambda args: self.do(args))(self)
Method 4
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).
Method 5
Late to the party, but I came here with a similar question: I have a class method and an instance, and want to apply the instance to the method.
At the risk of oversimplifying the OP’s question, I ended up doing something less mysterious that may be useful to others who arrive here (caveat: I’m working in Python 3 — YMMV).
Consider this simple class:
class Foo(object):
def __init__(self, value):
self._value = value
def value(self):
return self._value
def set_value(self, value):
self._value = value
Here’s what you can do with it:
>>> meth = Foo.set_value # the method >>> a = Foo(12) # a is an instance with value 12 >>> meth(a, 33) # apply instance and method >>> a.value() # voila - the method was called 33
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0