2009-10-14 4 views
6

サブクラスが関数の名前で属性を設定できるようにするクラスを記述する必要があります。その関数は、クラスのインスタンスから呼び出し可能でなければなりません。Pythonでコールバックを受け付けるクラスを記述していますか?

たとえば、サブクラスがウェルカムメッセージで渡すことができるFruitクラスを記述する必要があるとします。 Fruitクラスは、設定可能な属性print_callbackを公開する必要があります。

class Fruit(object): 
    print_callback = None 

    def __init__(self, *args, **kwargs): 
     super(Fruit, self).__init__(*args, **kwargs) 
     self.print_callback("Message from Fruit: ") 

が、私はこのコードによって消費することができているAPIを公開する必要があります(明確にするために、このコードは、それがあると言う、変更することはできません、サードパーティのコード):

def apple_print(f): 
    print "%sI am an Apple!" % f 

class Apple(Fruit): 
    print_callback = apple_print 

私が実行している場合:

mac = Apple() 

私が取得したい:

Message from Fruit: I am an Apple!

は、代わりに私が取得:

TypeError: apple_print() takes exactly 1 argument (2 given)

私は自分が最初の引数として渡されているので、これがあると思います。

どのようにしてFruitクラスを書くことができますか?ありがとう!

+1

を私はあなたがこのアプローチと、以下の優れたソリューションを持ってきた問題を感謝しています。しかし、これは 'print_callback'をメソッド(単に' print_me'と呼んで、それをオーバーライドするサブクラスを取得すること)として定義する必要があるように思えます。それは単純でpythonicになります。異なる種類の 'print_me'メソッドごとに異なるサブクラスを作成してください。 –

+0

私は、Google App Engineのgoogle.appengine.ext.db.djangoforms(DF2など)をサブクラス化して、DjangoのModelForm(django.forms.ModelForm)と同じ方法で属性formfield_callbackを上書きできるようにしたかった)。つまり、スーパークラスをdjango.forms.ModelFormに変更するだけで、標準のDjangoでは 'class f(DF2)'を使用できます。 Djangoの作者がformfield_callbackを属性として定義した理由は分かりません。 –

答えて

7

Pythonは、クラススコープ内にバインドされた関数はすべてメソッドであるとみなします。

def __init__(self, *args, **kwargs): 
    super(Fruit, self).__init__(*args, **kwargs) 

    # The attribute name was changed in Python 3; pick whichever line matches 
    # your Python version. 
    callback = self.print_callback.im_func # Python 2 
    callback = self.print_callback.__func__ # Python 3 

    callback("Message from Fruit: ") 
+0

また、関数に 'self'引数を追加するだけで、通常のメソッドのように動作させることができます。 –

+0

この質問によれば、コールバック定義は変更できません。 –

+1

また、Python 3.xでは、メソッドの 'im_func'属性が' __func__'に改名されたことにも気づく価値があります。 –

2

更新

これを試してみてください:staticmethodを使用するabourget's suggestionを取り入れ、あなたが関数として扱うしたい場合は、元の関数オブジェクトを取得するために、それらの属性に周りを掘るする必要があります。

def __init__(self, *args, **kwargs): 
    super(Fruit, self).__init__(*args, **kwargs) 

    # Wrap function back into a proper static method 
    self.print_callback = staticmethod(self.print_callback) 

    # And now you can do: 
    self.print_callback("Message from Fruit: ") 
3

あなたは直接使用することができます。

class Apple(Fruit): 
    print_callback = staticmethod(apple_print) 

か:最初のケースで

class Apple(Fruit): 
    print_callback = classmethod(apple_print) 

、あなたは一つのパラメータのみ(オリジナル)を取得します。 2番目のパラメータでは、2つのパラメータを受け取ります.1つ目は、呼び出されたクラスです。

これが役に立ちます。短くて複雑ではありません。

+1

"はクリアされていますが、このコードは変更できません。つまり、サードパーティのコード" –

0

メタクラスとビットdirtyerソリューションも用意されています:

def apple_print(f): 
    print "Apple " + f 

class FruitMeta(type): 
    def __new__(cls, name, bases, dct): 
     func = dct["print_callback"] 
     dct["print_callback"]=lambda x,f,func=func: func(f) 
     return type.__new__(cls,name,bases,dct) 

class Fruit(object): 
    __metaclass__ = FruitMeta 
    print_callback = None 
    def __init__(self): 
     super(Fruit,self).__init__() 
     self.print_callback("Msg ") 

class Apple(Fruit): 
    print_callback = apple_print 

mac = Apple()here 

それは、作成前にクラスを操作します!私はこの質問見つけたとき、私はもっとこのような何かを探していた

1

class Something: 
    def my_callback(self, arg_a): 
     print arg_a 

class SomethingElse: 
    def __init__(self, callback): 
     self.callback = callback 

something = Something() 
something_else = SomethingElse(something.my_callback) 
something_else.callback("It works...") 
関連する問題