web-dev-qa-db-ja.com

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

107
Dan Passaro

すべての関数もdescriptorsであるため、__get__メソッドを呼び出してバインドできます。

bound_handler = handler.__get__(self, MyWidget)

R. Hettingerの優れた ガイド 記述子です。


Keith'scomment から抜粋した自己完結型の例として:

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
159
Alex Martelli

これは 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>>
77
Kiv

Selfを含むクロージャーを作成しても、関数は技術的にバインドされませんが、同じ(または非常に類似した)根本的な問題を解決する代替方法です。簡単な例を次に示します。

self.method = (lambda self: lambda args: self.do(args))(self)
9
Keith Pinson

これにより、selfhandlerにバインドされます。

_bound_handler = lambda *args, **kwargs: handler(self, *args, **kwargs)
_

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

7
brian-brazil

パーティーに遅刻しましたが、同じような質問がありました。クラスメソッドとインスタンスがあり、インスタンスをメソッドに適用したいのです。

OPの質問を単純化しすぎて、私はここに到着した他の人に役立つかもしれない不思議なことをしました(注意:私はPython 3-YMMV)で作業しています。

この単純なクラスを考えてみましょう。

class Foo(object):

    def __init__(self, value):
        self._value = value

    def value(self):
        return self._value

    def set_value(self, value):
        self._value = value

これでできることは次のとおりです。

>>> meth = Foo.set_value   # the method
>>> a = Foo(12)            # a is an instance with value 12
>>> meth(a, 33)            # apply instance and method
>>> a.value()              # voila - the method was called
33
1
fearless_fool