2011-01-10 18 views
7

私はそれが呼び出される方法だと思いますが、私はそのための例を示します。デコレータクラスとデコレータ関数の違い

デコレータクラス:

class decorator(object): 
    def __init__(self, func): 
     self.func = func 

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

デコレータ機能:

def decorator(func): 
    def wrapper(*args, **kwargs): 
     print 'something' 
     return func(*args, **kwargs) 
    return wrapper 

は単なる好みの問題、どちらか一方を使用していますか?実際的な違いはありますか?

+3

違いがあります。違いは、通常の関数と通常の関数を使いたいときは全く同じです – Falmarri

答えて

10

デコレータを実装する関数を書くことができるなら、それを好むべきです。しかし、すべてのデコレータが関数として簡単に記述できるわけではありません。たとえば、内部状態を保存する場合などです。

class counted(object): 
    """ counts how often a function is called """ 
    def __init__(self, func): 
     self.func = func 
     self.counter = 0 

    def __call__(self, *args, **kwargs): 
     self.counter += 1 
     return self.func(*args, **kwargs) 


@counted 
def something(): 
    pass 

something() 
print something.counter 

自分自身を含めて人々は、機能だけでデコレータを書くというばかばかしい努力をしています。私はまだ、なぜクラスのオーバーヘッドが完全に無視できるのか分かりません。

+4

もちろん、*関数として書くことができます。しかし、Pythonでは、通常、クロージャーよりもクラスを優先して非表示にします。 –

+1

@Sven:そうです、私は本当に誇張していました。 –

+1

私は実際にPython(3.x)のこのバージョン(コメントは改行を食べるので、中括弧\ * sob \ *を使用しています)が好きです: 'def counted(f){x = 0; defラッパー(* args、** kwargs){非ローカルx; x + = 1; f(* args、** kwargs)}ラッパーを返す} '。 2.xのバージョンはシンプルですが(シングルトンリストを使用し、その単一のアイテムを使用して '非ローカル 'の欠点をハッキングします)。 – delnan

3

これは一般的に味の問題です。ほとんどのPythonプログラムはダックタイピングを使用しており、呼び出すことができるかどうかは、呼び出し可能な限り関数や他の型のインスタンスであるかどうかは実際には気にしません。 __call__()メソッドを持つものは呼び出し可能です。

関数スタイルのデコレータを使用するいくつかの利点があります:あなたのデコレータがラッパー関数を返す(すなわち、それはそれに何かをやった後、元の関数を返す、などはありません

  • 多くのクリーナーは、属性の設定として)。

  • 参照を元の関数に明示的に保存する必要はありません。これは、クロージャによって行われるためです。

  • functools.wraps()やMichele Simionatoの署名保持型decoratorモジュールのようなデコレータを作成するのに役立つツールのほとんどは、関数形式のデコレータで動作します。

  • ダックタイピングを使用しない関数がありますが、実際には関数型が必要なため、関数を置き換える関数を返すのは理論的には安全です。

これらの理由から、私はほとんどの場合、機能スタイルのデコレータを使用します。反例として、hereは、クラススタイルのデコレータが私にとってより自然な最近の例です。

+2

'functools.wraps()'は関数スタイルのデコレータで動作することを意図しているかもしれませんが、クラススタイルのデコレータの '__init__'にある' functools.update_wrapper(self、wrapped) 'は動作します完璧に。 –

関連する問題