Python:绑定一个未绑定的方法?

Dan*_*aro 108 python methods bind class

在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)
Run Code Online (Sandbox Code Playgroud)

问题是,由于所有的值handler都是未绑定的方法,我的程序在一个壮观的火焰中爆炸,我哭泣.

我在网上寻找解决方案似乎应该是一个相对简单,可解决的问题.不幸的是我找不到任何东西.现在,我正在functools.partial尝试解决这个问题,但有没有人知道是否有一种干净,健康,Pythonic的方式将未绑定的方法绑定到一个实例并继续传递它而不调用它?

Ale*_*lli 161

所有函数也都是描述符,因此您可以通过调用它们的__get__方法来绑定它们:

bound_handler = handler.__get__(self, MyWidget)
Run Code Online (Sandbox Code Playgroud)

这是R. Hettinger 对描述符的出色指南.

  • 因此,一个将函数绑定到类实例的函数:`bind = lambda instance,func,asname:setattr(instance,asname,func .__ get __(instance,instance .__ class __))`示例:`class A:pass;`` a = A();``bind(a,bind,'bind')` (9认同)
  • 那很酷.我喜欢你如何省略类型并取回一个"绑定方法?.f". (3认同)
  • 嗯,你每天都学到新东西.@Kazark至少在Python 3中,你也可以跳过提供类型,因为`__get__`将从object参数隐式地获取它.我甚至不确定提供它是否有任何作用,因为无论第一个参数是什么实例,我提供的类型与第二个参数无关.所以`bind = lambda instance,func,asname = None:setattr(instance,asname或func .__ name __,func .__ get __(instance))`也应该这样做.(虽然我更喜欢将"bind"用作个装饰者,但这是另一回事.) (2认同)
  • 哇,从来不知道函数是描述符。这是一个非常优雅的设计,方法只是类“__dict__”中的普通函数,属性访问通过正常的描述符协议为您提供未绑定或绑定的方法。我一直认为这是在“type.__new__()”期间发生的某种魔法 (2认同)

Kiv*_*Kiv 80

这可以使用types.MethodType干净地完成.例:

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>>
Run Code Online (Sandbox Code Playgroud)

  • +1这很棒,但是在你提供的URL的python文档中没有引用它. (10认同)
  • +1,我不想在我的代码中调用魔术函数(即`__get__`).我不知道你测试了哪个版本的python,但在python 3.4上,`MethodType`函数有两个参数.功能和实例.所以这应该改为`types.MethodType(f,C())`. (3认同)
  • 它实际上是在文档中提到的,但是在其他答案的描述符页面中:https://docs.python.org/3/howto/descriptor.html#functions-and-methods (2认同)

Kei*_*son 9

在其中创建一个带有self的闭包在技术上不会绑定该函数,但它是解决相同(或非常相似)底层问题的另一种方法.这是一个简单的例子:

self.method = (lambda self: lambda args: self.do(args))(self)
Run Code Online (Sandbox Code Playgroud)


bri*_*zil 7

这将绑定selfhandler:

bound_handler = lambda *args, **kwargs: handler(self, *args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

这通过self作为第一个参数传递给函数来工作.object.function()只是语法糖function(object).

  • 不,它不会,如果你执行bound_handler(),它只会调用该方法.定义lambda不会调用lambda. (9认同)
  • @Alan:你的第一个参数和`instancemethod`的`function`之间的区别是什么?鸭子打字看不出差别. (5认同)
  • @LieRyan的不同之处在于您仍然没有处理基本类型。`functools.partial`会删除一些元数据,例如`__module__`。(也想记录一下,当我对这个答案的第一个评论时,我会非常畏缩。)实际上,在我的问题中,我提到我已经在使用`functools.partial`了,但是我觉得必须要“更纯净”的方式,因为很容易获得未绑定和绑定的方法。 (2认同)