131

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 の方法があるかどうかを知っている人はいますか?

4

5 に答える 5

194

すべての関数は記述子__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
于 2009-06-18T21:54:29.527 に答える
89

これは、types.MethodTypeを使用してきれいに行うことができます。例:

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>>
于 2009-06-18T21:50:36.400 に答える
10

self を含むクロージャーを作成しても、技術的に関数をバインドすることはできませんが、同じ (または非常に類似した) 根本的な問題を解決する別の方法です。以下に簡単な例を示します。

self.method = (lambda self: lambda args: self.do(args))(self)
于 2011-09-05T19:31:03.830 に答える
9

これは以下にバインドselfhandlerます:

bound_handler = lambda *args, **kwargs: handler(self, *args, **kwargs)

selfこれは、関数の最初の引数として渡すことで機能します。object.function()の構文糖衣ですfunction(object)

于 2009-06-18T21:41:13.593 に答える