如何在不调用方法的情况下绑定未绑定的方法?
在Python中,有没有办法在不调用方法的情况下绑定一个未绑定的方法呢?
我正在写一个wxPython程序,对于某个类,我决定把所有按钮的数据放在一个类级别的元组列表中,像这样:
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)
问题是,由于所有的handler
值都是未绑定的方法,我的程序就像爆炸了一样,真让我伤心。
我在网上找了一下,想找个解决办法,感觉这个问题应该比较简单,应该能解决的。不幸的是,我没有找到任何相关的信息。目前,我在用functools.partial
来绕过这个问题,但有没有人知道有没有一种更简洁、更符合Python风格的方法,可以把未绑定的方法绑定到一个实例上,并且在不调用它的情况下继续传递呢?
6 个回答
12
闭包(closure),也叫做闭合表达式(closed expression),是指一种没有自由变量的表达式。自由变量就是在表达式中没有被定义的变量,而闭合表达式则是所有的变量都已经被定义了。
bound_handler = (lambda handler, self:
lambda *args, **kwargs: handler(self, *args, **kwargs)
)(handler, self)
在这里,handler
和self
是在内部的lambda表达式中的自由变量,而在外部的lambda表达式中它们是被绑定的变量。同时,args
和kwargs
在内部和外部的lambda表达式中都是被绑定的变量,因此外部的lambda表达式就是一个闭包。
97
这可以通过 types.MethodType
来实现:
import types
bound_handler = types.MethodType(handler, self)
215
所有的函数其实也可以被称为描述符,所以你可以通过调用它们的 __get__
方法来绑定它们:
bound_handler = handler.__get__(self, MyWidget)
这里有 R. Hettinger 的一篇很棒的 描述符指南。
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