次の原則をそのままにして、デコレータとして使用するクラスを構築したいと思います。
これはDjangoプロジェクト用であり、現在取り組んでいる特定のケースでは、メソッドに2つのデコレータが必要であり、通常のpython関数:
@AccessCheck
@AutoTemplate
def view(request, item_id) {}
@AutoTemplateは関数を変更して、HttpResponseを返す代わりに、コンテキストで使用する辞書を返すようにします。 RequestContextが使用され、テンプレート名はメソッド名とモジュールから推測されます。
@AccessCheckは、item_idに基づいてユーザーに追加のチェックを追加します。
コンストラクターを正しく取得して適切な属性をコピーするだけだと思いますが、これらはどの属性ですか?
次のデコレータは、私が説明するようには機能しません。
class NullDecl (object):
def __init__ (self, func):
self.func = func
def __call__ (self, * args):
return self.func (*args)
次のコードで示されているように:
@NullDecl
@NullDecl
def decorated():
pass
def pure():
pass
# results in set(['func_closure', 'func_dict', '__get__', 'func_name',
# 'func_defaults', '__name__', 'func_code', 'func_doc', 'func_globals'])
print set(dir(pure)) - set(dir(decorated));
さらに、NullDeclコンストラクターに "print func .name"を追加してみてください。名前が欠落しているため、最初のデコレーターでは機能しますが、2番目のデコレーターでは機能しません。
洗練されたeduffyの答えは少し、それはかなりうまくいくようです:
class NullDecl (object):
def __init__ (self, func):
self.func = func
for n in set(dir(func)) - set(dir(self)):
setattr(self, n, getattr(func, n))
def __call__ (self, * args):
return self.func (*args)
def __repr__(self):
return self.func
何もしないデコレータクラスは次のようになります。
class NullDecl (object):
def __init__ (self, func):
self.func = func
for name in set(dir(func)) - set(dir(self)):
setattr(self, name, getattr(func, name))
def __call__ (self, *args):
return self.func (*args)
そして、あなたはそれを普通に適用することができます:
@NullDecl
def myFunc (x,y,z):
return (x+y)/z
デコレータモジュール は、署名を保持するデコレータを作成するのに役立ちます。
そして PythonDecoratorLibrary はデコレータの便利な例を提供するかもしれません。
関数を元の関数と見分けがつかないようにラップするデコレータを作成するには、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))