I want to use a decorator to do some preparation job and record the status the function have, so I write something like that:
class Decorator:
def __init__(self, func):
self.count = 0
self.func = func
def __call__(self, *args, **kwargs):
self.count += 1 # Simply count the call times
return self.func(self, *args, **kwargs)
class Foo:
def __init__(self):
self.value = 0
@Decorator
def test(self, value):
self.value = value # change the value of instance
print(self.value)
f = Foo()
f.test(1)
print(f.value)
print(f.test.value)
But it's obvious that self
in __call__(self, *args, **kwargs)
corresponds to instance of Decorator
instead of the instance of Foo
, which will make f.value
unchanged but f.test.value
increase .
Is there any way I can pass the instance of Foo
to Decorator
instead of Decorator
itself?
Or is there any way to implement this function much more clear?
As the decorator is only called once and replaces the method for all instance with one instance of the Decorator class. All it does is:
Foo.test = Decorator(Foo.test)
This makes it impossible to detect the instance called. One work-around would be to apply the decorator in the __init__
of Foo
by hand:
class Foo:
def __init__(self):
self.value = 0
self.test = Decorator(self.test)
def test(self, value):
self.value = value # change the value of instance
print(self.value)
This way the decorator wraps the instance method, so you do not need to pass self
in the __call__
of Decorator
:
class Decorator:
def __init__(self, func):
self.count = 0
self.func = func
def __call__(self, *args, **kwargs):
self.count += 1 # Simply count the call times
return self.func(*args, **kwargs)
Now it works and you have to update you test method, as f.test.value
no longer exists:
f = Foo()
f.test(1)
print(f.value)
It outputs two times a 1
as expected.