誰もこれに言及しなかったので、特にデコレータが複雑で、それを複数のメソッド(関数)に分割したい場合に、私がよりエレガントだと思う呼び出し可能クラスを利用するソリューションもあります。このソリューションは、__new__
魔法の方法を利用して、本質的に他の人が指摘したことを実行します。リターンを適切に調整するよりも、最初にデコレータがどのように使用されたかを検出します。
class decorator_with_arguments(object):
def __new__(cls, decorated_function=None, **kwargs):
self = super().__new__(cls)
self._init(**kwargs)
if not decorated_function:
return self
else:
return self.__call__(decorated_function)
def _init(self, arg1="default", arg2="default", arg3="default"):
self.arg1 = arg1
self.arg2 = arg2
self.arg3 = arg3
def __call__(self, decorated_function):
def wrapped_f(*args):
print("Decorator arguments:", self.arg1, self.arg2, self.arg3)
print("decorated_function arguments:", *args)
decorated_function(*args)
return wrapped_f
@decorator_with_arguments(arg1=5)
def sayHello(a1, a2, a3, a4):
print('sayHello arguments:', a1, a2, a3, a4)
@decorator_with_arguments()
def sayHello(a1, a2, a3, a4):
print('sayHello arguments:', a1, a2, a3, a4)
@decorator_with_arguments
def sayHello(a1, a2, a3, a4):
print('sayHello arguments:', a1, a2, a3, a4)
デコレータが引数とともに使用される場合、これは次のようになります。
result = decorator_with_arguments(arg1=5)(sayHello)(a1, a2, a3, a4)
引数arg1
がコンストラクターに正しく渡され、装飾された関数がに渡されることがわかります。__call__
しかし、デコレータが引数なしで使用される場合、これは次のようになります。
result = decorator_with_arguments(sayHello)(a1, a2, a3, a4)
この場合、装飾された関数がコンストラクターに直接渡され、の呼び出し__call__
が完全に省略されていることがわかります。そのため、__new__
魔法の方法でこのケースを処理するためにロジックを使用する必要があります。
__init__
代わりに使用できないのはなぜ__new__
ですか?理由は単純です:pythonはNone以外の値をから返すことを禁止しています__init__
警告
このアプローチには1つの副作用があります。関数のシグネチャは保持されません!
@redirect_output
は非常に有益ではありません。それは悪い考えだと思います。最初のフォームを使用して、あなたの人生をたくさん簡素化してください。