2009-06-18 6 views
92

Pythonでは、バインドされていないメソッドを呼び出さずにバインドする方法はありますか?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の方法があれば誰にも分かりますか?これは、関数の最初の引数としてselfを渡すことによって動作

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

+1

は「未結合の方法」 – Christopher

+4

@Christopher定義 - あなたが明示的に自己を渡すために持っているので、それはから吸い込まれたオブジェクトの範囲にバインドされていない方法を。 –

答えて

143

すべての機能は、またディスクリプタです。

+2

これはかなりクールです。私はあなたがタイプを省略し、代わりに "束縛メソッド?.f"を返すのが好きです。 – Kiv

+0

私は 'MethodType'の引数が少し上に変更されている間に、それはpy3kで同じように動作するので、' MethodType'よりもこの解決策が気に入っています。 – bgw

+8

したがって、関数をクラスインスタンスにバインドする関数: 'bind = lambda instance、func、asname:setattr(インスタンス、asname、func .__ get __(インスタンス、インスタンス.__クラス__))' 例: 'class A: " ' a = A(); ' ' bind(a、bind、 'bind') ' –

3

これはselfhandlerにバインドします。 object.function()は、function(object)の構文砂糖です。

+1

はい、これはメソッドを呼び出します。問題は、呼び出し可能なオブジェクトとしてバインドされたメソッドを渡すことができる必要があることです。私はバインドされていないメソッドとそれにバインドしたいインスタンスを持っていますが、すぐに呼び出さずにすべてをまとめておく方法を見つけることはできません –

+6

いいえ、それはメソッドdo bound_handler()を実行します。ラムダを定義してもラムダは呼び出されません。 –

+0

ラムダを定義する代わりに、実際には 'functools.partial'を使用することができます。しかし、それは正確な問題を解決しません。あなたは 'instancemethod'ではなく' function'を扱っています。 –

68

これはtypes.MethodTypeできれいに行うことができます。例:

bound_handler = handler.__get__(self, MyWidget) 

ここで記述子へのR.ヘッティンガーの優れたguideです:あなたは自分の__get__メソッドを呼び出すことによって、それらをバインドすることができるように

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>> 
+8

+1これは素晴らしいですが、提供したURLのPythonドキュメントにはこれに関する参照はありません。 –

+2

+1、自分のコードで魔法の関数を呼び出すことを好まない(つまり '__get__')。これをテストしたPythonのバージョンはわかりませんが、Python 3.4では 'MethodType'関数は2つの引数をとります。関数とインスタンス。したがって、これは 'types.MethodType(f、C())'に変更する必要があります。 –

+0

ここにあります!インスタンスメソッドをパッチするには良い方法です: 'wgt.flush = types.MethodType(lambda self:None、wgt)' – Winand

7

自己でクロージャを作成することは、技術的に関数をバインドすることはありませんが、同じ(または非常に類似した)根本的な問題を解決する別の方法です。ここでは簡単な例です:

​​