37


18

以下の原則をそのまま使用して、デコレータとして使用するクラスを構築したいです。

  1. 1つの関数の上に、そのようなクラスデコレータを複数スタックすることが可能です。

  2. 結果の関数名ポインタはデコレータなしで同じ関数と見分けがつかないはずです。たぶんそれがどのタイプ/クラスであるかのためだけに保存​​してください。

  3. 実際にデコレータによって指示されていない限り、デコレータの注文は関係ありません。 すなわち 独立したデコレータは任意の順序で適用できます。

これはDjangoプロジェクトのためのもので、私が今取り組んでいる特定のケースでは2つのデコレータが必要です。そして通常のpython関数として表示されます。

@AccessCheck @AutoTemplate defビュー(リクエスト、アイテムID){}

@AutoTemplateは、HttpResponseを返すのではなく、コンテキストで使用するための辞書を返すように関数を変更します。 RequestContextが使用され、テンプレート名はメソッド名とモジュールから推測されます。

@AccessCheckは、item_idに基づいてユーザーに追加のチェックを追加します。

コンストラクタを正しく取得して適切な属性をコピーすることだけが目的だと思いますが、これらの属性はどれですか。

以下のデコレータは私が説明したようには動作しません。

クラスNullDecl(オブジェクト):def __init__(self、func):self.func = func def __call__(self、* args):return self.func(* args)

次のコードで示されるように:

@NullDecl @NullDecl def decoration():渡す

def pure():渡す

#結果はset(['' func_closure '、' func_dict '、' __get__ '、' func_name '、#' func_defaults '、' __name__ '、' func_doc '、' func_globals '])になります。print set(dir(pure )) - セット(ディレクトリ(装飾))。

さらに、NullDeclコンストラクタに "print func。* name *"を追加して試してみてください。最初のデコレータでは機能しますが、2番目のデコレータでは機能しません。名前が表示されないためです。

洗練された* eduffy *の答えは少しあります、そしてそれはかなりうまくいくようです:

クラスNullDecl(オブジェクト):def __init__(self、func):set(dir(func))内のnに対するself.func = func  -  set(dir(self)):setattr(self、n、getattr(func、n) )

def __call__(self、* args):戻りself.func(* args)def __repr __(self):戻りself.func

3 Answer


22


何もしないデコレータクラスは次のようになります。

クラスNullDecl(object):定義__init__(self、func):set(dir(func))内の名前に対するself.func = func  -  set(dir(self)):setattr(self、name、getattr(func、name) )

def __call__(self、* args):self.func(* args)を返します。

そして、あなたは普通にそれを適用することができます:

@NullDecl def myFunc(x、y、z):return(x y)/ z


10


http://pypi.python.org/pypi/decorator[decoratorモジュール]は、シグネチャ保存デコレータを書くのに役立ちます。

そして PythonDecoratorLibraryはデコレータのための有用な例を提供するかもしれません。


7


元の関数と区別できないように関数をラップするデコレーターを作成するには、 `+ functools.wraps +`を使用します。

例:

def mydecorator(func):
    @functools.wraps(func):
    def _mydecorator(*args, **kwargs):
        do_something()
        try:
            return func(*args, **kwargs)
        finally:
            clean_up()
    return _mydecorator

# ... and with parameters
def mydecorator(param1, param2):
    def _mydecorator(func):
        @functools.wraps(func)
        def __mydecorator(*args, **kwargs):
            do_something(param1, param2)
            try:
                return func(*args, **kwargs)
            finally:
                clean_up()
        return __mydecorator
    return _mydecorator

(私の個人的な好みはクラスではなく関数を使ってデコレータを作成することです)

デコレータの順序は次のとおりです。

@d1
@d2
def func():
    pass

# is equivalent to
def func():
    pass

func = d1(d2(func))