如何在不调用方法的情况下绑定未绑定的方法?

144 投票
6 回答
67017 浏览
提问于 2025-04-15 12:21

在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)

在这里,handlerself是在内部的lambda表达式中的自由变量,而在外部的lambda表达式中它们是被绑定的变量。同时,argskwargs在内部和外部的lambda表达式中都是被绑定的变量,因此外部的lambda表达式就是一个闭包。

97

这可以通过 types.MethodType 来实现:

import types

bound_handler = types.MethodType(handler, self)
215

所有的函数其实也可以被称为描述符,所以你可以通过调用它们的 __get__ 方法来绑定它们:

bound_handler = handler.__get__(self, MyWidget)

这里有 R. Hettinger 的一篇很棒的 描述符指南


以下是一个完整的例子,来自 Keith评论

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

撰写回答