How to bind an unbound method without calling it?
Question:
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 would 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 am 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:
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. obj.f()
is just syntactic sugar for f(obj)
.
This can be done with types.MethodType
:
import types
bound_handler = types.MethodType(handler, self)
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
With a closure, also known as a closed expression (as opposed to an open expression), which is an expression without free variables:
bound_handler = (lambda self:
lambda *args, **kwargs: handler(self, *args, **kwargs)
)(self)
Here args
and kwargs
are bound variables in both the inner and outer lambda expressions, and self
is a free variable in the inner lambda expression and a bound variable in the outer lambda expression, so the outer lambda expression is a closure.
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
To expand on @Keith Pinson’s answer which uses a closure and @brian-brazil’s answer which doesn’t, here is why the former is correct.
Example with a closure (__get__
, types.MethodType
, and functools.partial
have the same behavior):
def handler(self, *args, **kwargs):
return self
self = True
bound_handler = (lambda self:
lambda *args, **kwargs: handler(self, *args, **kwargs)
)(self)
bound_handler() # returns True
self = False
bound_handler() # returns True
Example without a closure:
def handler(self, *args, **kwargs):
return self
self = True
bound_handler = lambda *args, **kwargs: handler(self, *args, **kwargs)
bound_handler() # returns True
self = False
bound_handler() # returns False
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 would 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 am 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?
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. obj.f()
is just syntactic sugar for f(obj)
.
This can be done with types.MethodType
:
import types
bound_handler = types.MethodType(handler, self)
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
With a closure, also known as a closed expression (as opposed to an open expression), which is an expression without free variables:
bound_handler = (lambda self:
lambda *args, **kwargs: handler(self, *args, **kwargs)
)(self)
Here args
and kwargs
are bound variables in both the inner and outer lambda expressions, and self
is a free variable in the inner lambda expression and a bound variable in the outer lambda expression, so the outer lambda expression is a closure.
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
To expand on @Keith Pinson’s answer which uses a closure and @brian-brazil’s answer which doesn’t, here is why the former is correct.
Example with a closure (__get__
, types.MethodType
, and functools.partial
have the same behavior):
def handler(self, *args, **kwargs):
return self
self = True
bound_handler = (lambda self:
lambda *args, **kwargs: handler(self, *args, **kwargs)
)(self)
bound_handler() # returns True
self = False
bound_handler() # returns True
Example without a closure:
def handler(self, *args, **kwargs):
return self
self = True
bound_handler = lambda *args, **kwargs: handler(self, *args, **kwargs)
bound_handler() # returns True
self = False
bound_handler() # returns False