我想要一个装饰器,我可以将其用作@decorator和decorator()以及类方法,如下所示:
def decorator_with_args(name):
print(f'Hello {name} !')
def decorator(func):
def wrapper(self, *args, **kwargs):
print(f'Hello {self.title} {name} again !!')
print(f"Calling {func.__name__} with instance {self}...")
result = func(self, *args, **kwargs)
print(f"{func.__name__} finished. Result: {result}")
return result
return wrapper
return decorator
class Calculator:
def __init__(self):
self.title = 'Mr'
@decorator_with_args('World')
def add(self, a, b):
return a + b
def add2(self, a, b):
return a + b
def do_add(self, a, b):
return decorator_with_args(f'World{a}')(self.add2)(self, a, b)
# Usage 1
calc = Calculator()
result = calc.add(3, 5)
# Usage 2
calc = Calculator()
result = calc.do_add(3, 5)
之所以要用装饰器函数作为上面两种表示是因为:
虽然
@decorator_with_args
按预期工作[用法 1],但我在 decorator_with_args()
[用法 2] 时收到错误。我尝试了一些方法,但没有一个对后者起作用。
如果我尝试通过
(self, a, b)
,例如 decorator_with_args(f'World{a}')(self.add2)(self, a, b)
,我会得到 TypeError: add2() takes 3 positional arguments but 4 were given
。
另一方面,如果我尝试在没有
(a, b)
的情况下通过 self
,例如 decorator_with_args(f'World{a}')(self.add2)(a, b)
,我会得到 AttributeError: 'int' object has no attribute 'title'
。
我很高兴可能存在其他类似的问题,我尝试搜索这些问题,但无法让它们适合我的用例。
为了复制实例方法的标准装饰,您需要装饰绑定到该方法的底层 function,而不是方法本身 - 这是因为
self.add2
隐式添加 self
作为该函数的第一个参数,所以它加倍了。
def do_add(self, a, b):
return decorator_with_args(f'World{a}')(Calculator.add2)(self, a, b)
或
def do_add(self, a, b):
return decorator_with_args(f'World{a}')(self.add2.__func__)(self, a, b)