4

私がやりたいことは次のようなものです:

class Foo(object):
    def __init__(self):
        pass
    def f(self):
        print "f"
    def g(self):
        print "g"


# programatically set the "default" operation
fer=Foo()
fer.__call__=fer.f

# a different instance does something else as its
# default operation
ger=Foo()
ger.__call__=ger.g

fer()  # invoke different functions on different
ger()  # objects depending on how they were set up.

しかし、2.7(現在使用しています)の時点では、これを行うことはできません。試行するとfer() 例外が発生します。

事実上、インスタンスごとの__call__メソッドを設定する方法はありますか?

4

3 に答える 3

3

残念ながら、ここでは特殊な方法である ため、通常の方法はtypes.MethodType機能しません。__call__

データモデルから:

クラス インスタンスは、クラスに__call__()メソッドがある場合にのみ呼び出すことができます。x(arguments) は の省略形ですx.__call__(arguments)

これは実際に何が呼び出されるかについては少しあいまいですが、クラスにメソッドが必要であることは明らかです。__call__

ある種のハックを作成する必要があります。

class Foo(object):
    def __init__(self):
        pass
    def f(self):
        print "f"
    def g(self):
        print "g"

    def __call__(self):
        return self.__call__()

f = Foo()
f.__call__ = f.f
f()

g = Foo()
g.__call__ = g.g
g()

__call__ただし、これには注意してください。インスタンスを呼び出す前にインスタンスにa を設定しないと、無限再帰が発生します。

rebind するマジック属性を実際に呼び出すことはお勧めしません__call__。ここでのポイントは、python が変換することを実証することです:f()f.__class__.__call__(f)、インスタンスごとに変更するためにできることは何もありません。クラス__call__は何をしても呼び出されます-クラスの__call__インスタンスごとの動作を変更するために何かをする必要があるだけです。これは簡単に実現できます。


セッター型のものを使用して、(単純な関数ではなく) 実際にクラスにメソッドを作成できます。もちろん、それをプロパティに変換することもできます。

import types
class Foo(object):
    def __init__(self):
        pass
    def f(self):
        print "f"
    def g(self):
        print "g"

    def set_func(self,f):
        self.func = types.MethodType(f,self)

    def __call__(self,*args,**kwargs):
        self.func(*args,**kwargs)

f = Foo()
f.set_func(Foo.f)
f()

def another_func(self,*args):
    print args

f.set_func(another_func)
f(1,2,3,"bar")
于 2013-01-29T16:03:46.767 に答える
2

間違った問題を解決しようとしている可能性があります。

Python では手続き型のクラス作成が可能であるため、次のようなコードを記述できます。

>>> def create_class(cb):
...     class Foo(object):
...         __call__ = cb
...     return Foo
... 
>>> Foo1 = create_class(lambda self: 42)
>>> foo1 = Foo1()
>>> foo1()
>>> Foo2 = create_class(lambda self: self.__class__.__name__)
>>> foo2 = Foo2()
>>> foo2()

この場合、Foo1 と Foo2 には共通の基本クラスがないことに注意してください。したがってisinstance、機能しissubclassません。それらに共通の基本クラスが必要な場合は、次のコードを使用します。

>>> class Foo(object):
...     @classmethod
...     def create_subclass(cls, cb):
...          class SubFoo(cls):
...               __call__ = cb
...          return SubFoo
... 
>>> Foo1 = Foo.create_subclass(lambda self: 42)
>>> foo1 = Foo1()
>>> foo1()
>>> Foo2 = Foo.create_subclass(lambda self: self.__class__.__name__)
>>> foo1 = Foo2()
>>> foo2()
'Foo'
>>> issubclass(Foo1, Foo)
True
>>> issubclass(Foo2, Foo)
True

きれいなクラス階層を提供し、私には非常にきれいに見える 2 番目の方法が本当に気に入っています。

于 2013-01-29T16:15:29.927 に答える
1

考えられる解決策:

class Foo(object):
    def __init__(self):
        self._callable = lambda s: None
    def f(self):
        print "f"
    def set_callable(self, func):
        self._callable = func
    def g(self):
        print "g"
    def __call__(self):
        return self._callable()
d = Foo()
d.set_callable(d.g)
于 2013-01-29T16:01:23.013 に答える