関数の最初の引数に変換を適用する関数デコレータを書いています。関数を1回だけ装飾すると問題なく動作しますが、2回装飾するとエラーが発生します。以下は問題を示すいくつかのコードです、それは私が取り組んでいるコードの単純化されたバージョンです。問題を邪魔しないように、変換を行うコードを除外しました
from inspect import getargspec
from functools import wraps
def dec(id):
def _dec(fn):
@wraps(fn)
def __dec(*args, **kwargs):
if len(args):
return fn(args[0], *args[1:], **kwargs)
else:
first_arg = getargspec(fn).args[0]
new_kwargs = kwargs.copy()
del new_kwargs[first_arg]
return fn(kwargs[first_arg], **new_kwargs)
return __dec
return _dec
@dec(1)
def functionWithOneDecorator(a, b, c):
print "functionWithOneDecorator(a = %s, b = %s, c = %s)" % (a, b, c)
@dec(1)
@dec(2)
def functionWithTwoDecorators(a, b, c):
print "functionWithTwoDecorators(a = %s, b = %s, c = %s)" % (a, b, c)
functionWithOneDecorator(1, 2, 3)
functionWithOneDecorator(1, b=2, c=3)
functionWithOneDecorator(a=1, b=2, c=3)
functionWithOneDecorator(c=3, b=2, a=1)
functionWithTwoDecorators(1, 2, 3)
functionWithTwoDecorators(1, b=2, c=3)
functionWithTwoDecorators(a=1, b=2, c=3)
functionWithTwoDecorators(c=3, b=2, a=1)
上記のコードを実行すると、次の出力が得られます。
functionWithOneDecorator(a = 1, b = 2, c = 3)
functionWithOneDecorator(a = 1, b = 2, c = 3)
functionWithOneDecorator(a = 1, b = 2, c = 3)
functionWithOneDecorator(a = 1, b = 2, c = 3)
functionWithTwoDecorators(a = 1, b = 2, c = 3)
functionWithTwoDecorators(a = 1, b = 2, c = 3)
IndexError: list index out of range
これは、2番目のデコレータが関数を検査するときに、引数名を見つけるためにデコレーションしているのに失敗し、デコレータをデコレータしているために失敗し、*argsと**kwargsしか受け取らないためです。
上記のコードで機能する問題を回避する方法を考えることができますが、関数が私のデコレータとサードパーティの別のデコレータで装飾されている場合はまだ壊れます。これを修正する一般的な方法はありますか?または同じ結果を達成するためのより良い方法はありますか?
更新:デコレータモジュールを指摘してくれた@Hernanに感謝します。この問題を正確に解決します。これで、私のコードは次のようになります。
from decorator import decorator
def dec(id):
@decorator
def _dec(fn, *args, **kwargs):
return fn(args[0], *args[1:], **kwargs)
return _dec
@dec(1)
def functionWithOneDecorator(a, b, c):
print "functionWithOneDecorator(a = %s, b = %s, c = %s)" % (a, b, c)
@dec(1)
@dec(2)
def functionWithTwoDecorators(a, b, c):
print "functionWithTwoDecorators(a = %s, b = %s, c = %s)" % (a, b, c)
functionWithOneDecorator(1, 2, 3)
functionWithOneDecorator(1, b=2, c=3)
functionWithOneDecorator(a=1, b=2, c=3)
functionWithOneDecorator(c=3, b=2, a=1)
functionWithTwoDecorators(1, 2, 3)
functionWithTwoDecorators(1, b=2, c=3)
functionWithTwoDecorators(a=1, b=2, c=3)
functionWithTwoDecorators(c=3, b=2, a=1)
はるかにきれいで、それは機能します!