パラメータの有無にかかわらず使用できるデコレータを作成したいと思います:このような何か:
class d(object):
def __init__(self,msg='my default message'):
self.msg = msg
def __call__(self,fn):
def newfn():
print self.msg
return fn()
return newfn
@d('This is working')
def hello():
print 'hello world !'
@d
def too_bad():
print 'does not work'
私のコードでは、パラメーター付きのデコレーターの使用のみが機能しています。両方を機能させるにはどうすればよいですか(パラメーターありとパラメーターなし)。
例を見つけました、_@trace
_または@trace('msg1','msg2')
を使用できます:いいですね!
_def trace(*args):
def _trace(func):
def wrapper(*args, **kwargs):
print enter_string
func(*args, **kwargs)
print exit_string
return wrapper
if len(args) == 1 and callable(args[0]):
# No arguments, this is the decorator
# Set default values for the arguments
enter_string = 'entering'
exit_string = 'exiting'
return _trace(args[0])
else:
# This is just returning the decorator
enter_string, exit_string = args
return _trace
_
パラメータをデコレータに渡したい場合は、alwaysを関数として呼び出す必要があります。
@d()
def func():
pass
それ以外の場合は、パラメーターの違いを検出する必要があります。つまり、呼び出し側の意味を魔法のように推測する必要があります。推測する必要があるAPIを作成しないでください。あなたが最初に何を意味するかを一貫して言います。
つまり、関数はデコレータまたはデコレータファクトリのいずれかである必要があります。両方ではいけません。
値を格納するだけの場合は、クラスを作成する必要はありません。
def d(msg='my default message'):
def decorator(func):
def newfn():
print msg
return func()
return newfn
return decorator
@d('This is working')
def hello():
print 'hello world !'
@d()
def hello2():
print 'also hello world'
名前付き引数の使用に依存しても構わない場合は、必要なものに似たものを作成しました。
def cached_property(method=None, get_attribute=lambda a: '_%s_cached' % (a,)):
"""
Caches an object's attribute.
Can be used in the following forms:
@cached_property
@cached_property()
@cached_property(get_attribute=lambda x: 'bla')
@param method: the method to memoizes
@param get_attribute: a callable that should return the cached attribute
@return a cached method
"""
def decorator(method):
def wrap(self):
private_attribute = get_attribute(method.__name__)
try:
return getattr(self, private_attribute)
except AttributeError:
setattr(self, private_attribute, method(self))
return getattr(self, private_attribute)
return property(wrap)
if method:
# This was an actual decorator call, ex: @cached_property
return decorator(method)
else:
# This is a factory call, ex: @cached_property()
return decorator
これが機能するのは、キーワード以外の引数が1つしかなく、修飾された関数がデコレーターに渡されるためです。
装飾された関数に渡された引数(この場合は 'self')も使用したことに注意してください。
これはうまくいくでしょう。
def d(arg):
if callable(arg):
def newfn():
print('my default message')
return arg()
return newfn
else:
def d2(fn):
def newfn():
print(arg)
return fn()
return newfn
return d2
@d('This is working')
def hello():
print('hello world !')
@d # No explicit arguments.
def hello2():
print('hello2 world !')
@d('Applying it twice')
@d('Would also work')
def hello3():
print('hello3 world !')
hello()
hello2()
hello3()
出力:
This is working
hello world !
my default message
hello2 world !
Applying it twice
Would also work
hello3 world !
デコレータ関数の場合@
invocationには明示的な引数は渡されず、次のdef
で定義された関数を使用して呼び出されます。 isが引数を渡した場合、最初にそれらが呼び出され、次にthat予備呼び出しの結果(それ自体も呼び出し可能でなければならない)が次の関数で呼び出されます定義された。どちらの方法でも、最後の呼び出しまたは唯一の呼び出しの戻り値は、定義された関数名にバインドされます。
デコレータへの引数が関数かどうかを検出し、その場合は単純なデコレータを使用する必要があります。そして、パラメータ化されたデコレータに関数のみを渡す必要がないことを期待する必要があります。