如何使用类decorator计数实例方法调用



目标是计算使用类decorator的实例方法调用。我选择了类decorator,因为我想为每个装饰的实例方法分别存储字段call_count。函数装饰器不能解决这个问题,因为开发人员应该手动向具有装饰方法的类添加字段call_count,或者向装饰器函数添加属性字段call_coount。第一种情况不遵循OOP范式,而且还有额外的工作。在第二种情况下,函数属性保持所有装饰实例方法的计数(实例数量乘以装饰方法数量(。结果我想得到这样的调用计数:instance_name.method_name.call_count。我在这里研究了类似的问题,并尝试了所有的问题,但都解决不了问题。函数的decorator没有帮助,因为decorated方法不接收类实例:

class Wrapper(object):
def __init__(self, func):
self.call_count = 0
self.func = func
def __call__(self, *args, **kwargs):
self.call_count += 1
return self.func(*args, **kwargs)

class SomeBase:
def __init__(self):
self._model = " World"
@Wrapper
async def create(self, arg_1, arg_2):
return arg_1 + self._model + arg_2

async def test_wrapper():
base = SomeBase()
result = await base.create("hello", "!")
await base.create("hello", "!")
assert result == "hello World!"
assert base.create.call_count == 2

我得到一个错误:

test_call_count.py::test_wrapper FAILED
utils/tests/test_call_count.py:95 (test_wrapper)
async def test_wrapper():
base = SomeBase()
>       result = await base.create("hello", "!")
test_call_count.py:98: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
self = <utils.tests.test_call_count.Wrapper object at 0x7f8c10f8b310>
args = ('hello', '!'), kwargs = {}
def __call__(self, *args, **kwargs):
self.call_count += 1
>       return self.func(*args, **kwargs)
E       TypeError: create() missing 1 required positional argument: 'arg_2'
test_call_count.py:84: TypeError

如何解决这个问题?

这可以通过重写__get__方法来实现,该方法的第一个参数包含其方法被修饰的实际类的实例。如果保存此参数,则可以在__call__方法中重用它,将其作为实际方法的第一个参数传递:

class Wrapper(object):
def __init__(self, func):
self.call_count = 0
self.decorated_instance = None
self.func = func
def __call__(self, *args, **kwargs):
self.call_count += 1
return self.func(self.decorated_instance, *args, **kwargs)
def __get__(self, obj, objtype):
self.decorated_instance = obj
return self

最新更新