私はPythonデコレータの多くの例を見てきました:
__init__
、__get__
、__call__
の実装)しかし、上記のすべてを実行できる単一の例を見たことがなく、特定の質問( this one など)に対するさまざまな回答から合成することに問題があります。 this one または this one(これは私が今まで見た中で最高の答えの1つです) )、上記のすべてを組み合わせる方法。
私が欲しいのはclass-basedデコレータメソッドまたは関数、および 1つの追加パラメーター。つまり、次のように機能します。
class MyDecorator(object):
def __init__(self, fn, argument):
self.fn = fn
self.arg = argument
def __get__(self, ....):
# voodoo magic for handling distinction between method and function here
def __call__(self, *args, *kwargs):
print "In my decorator before call, with arg %s" % self.arg
self.fn(*args, **kwargs)
print "In my decorator after call, with arg %s" % self.arg
class Foo(object):
@MyDecorator("foo baby!")
def bar(self):
print "in bar!"
@MyDecorator("some other func!")
def some_other_function():
print "in some other function!"
some_other_function()
Foo().bar()
そして私は見ることを期待します:
In my decorator before call, with arg some other func!
in some other function!
In my decorator after call, with arg some other func!
In my decorator before call, with arg foo baby!
in bar!
In my decorator after call, with arg foo baby!
編集:それが重要な場合は、Python 2.7。
記述子をいじる必要はありません。 __call__()
メソッド内にラッパー関数を作成して返すだけで十分です。標準Python関数は、コンテキストに応じて、常にメソッドまたは関数として機能できます。
_class MyDecorator(object):
def __init__(self, argument):
self.arg = argument
def __call__(self, fn):
@functools.wraps(fn)
def decorated(*args, **kwargs):
print "In my decorator before call, with arg %s" % self.arg
fn(*args, **kwargs)
print "In my decorator after call, with arg %s" % self.arg
return decorated
_
このデコレータを次のように使用するとどうなるかについて少し説明します。
_@MyDecorator("some other func!")
def some_other_function():
print "in some other function!"
_
1行目はMyDecorator
のインスタンスを作成し、_"some other func!"
_を引数として__init__()
に渡します。このインスタンスを_my_decorator
_と呼びましょう。次に、装飾されていない関数オブジェクト(_bare_func
_と呼びましょう)が作成され、デコレータインスタンスに渡されるので、my_decorator(bare_func)
が実行されます。これによりMyDecorator.__call__()
が呼び出され、ラッパー関数が作成されて返されます。最後に、このラッパー関数は_some_other_function
_という名前に割り当てられます。
レベルがありません。
コードを検討する
class Foo(object):
@MyDecorator("foo baby!")
def bar(self):
print "in bar!"
このコードと同じです
class Foo(object):
def bar(self):
print "in bar!"
bar = MyDecorator("foo baby!")(bar)
したがって、MyDecorator.__init__
は"foo baby!"
で呼び出され、次にMyDecorator
オブジェクトは関数bar
で呼び出されます。
おそらくあなたはもっと何かを実装することを意味します
import functools
def MyDecorator(argument):
class _MyDecorator(object):
def __init__(self, fn):
self.fn = fn
def __get__(self, obj, type=None):
return functools.partial(self, obj)
def __call__(self, *args, **kwargs):
print "In my decorator before call, with arg %s" % argument
self.fn(*args, **kwargs)
print "In my decorator after call, with arg %s" % argument
return _MyDecorator
デコレータのタイプのリストで、引数を取るかどうかに関係なく、デコレータを見逃しました。この例は、「関数スタイルデコレータ(関数のラッピング)」を除くすべてのタイプをカバーしていると思います
class MyDecorator(object):
def __init__(self, argument):
if hasattr('argument', '__call__'):
self.fn = argument
self.argument = 'default foo baby'
else:
self.argument = argument
def __get__(self, obj, type=None):
return functools.partial(self, obj)
def __call__(self, *args, **kwargs):
if not hasattr(self, 'fn'):
self.fn = args[0]
return self
print "In my decorator before call, with arg %s" % self.argument
self.fn(*args, **kwargs)
print "In my decorator after call, with arg %s" % self.argument
class Foo(object):
@MyDecorator("foo baby!")
def bar(self):
print "in bar!"
class Bar(object):
@MyDecorator
def bar(self):
print "in bar!"
@MyDecorator
def add(a, b):
print a + b