The following is my test code to have a decorator for a class method which can change the self (current object instance)
class Test(object):
def __init__(self):
self.x = 5
def _change_x(self):
print "in _change_x"
def decorator(f):
print "in decorator"
def wrapped(*args, **kwargs):
print "in wrapped"
print args, kwargs
self.x = 8
f(*args, **kwargs)
return wrapped
return decorator
@_change_x
def print_x(self):
print "in print_x, x: %d" % self.x
return self.x
if __name__ == "__main__":
test = Test()
print "Initial value for x: %d" % test.x
print "Test if it changed? x: %d" % test.print_x()
The internal method wrapped in the decorator is not being invoked. Can any one help me pointing out the mistake in my test code. I want this kind of decorator defined in a class, and is used to decorate few methods in that class to change the class members at the call time.
First, lets consider why your code doesn't work...
At the time when _change_x
is invoked, the class is still under construction, so there can't be any instances of the class. Because of this, your self
argument is misleading. When it gets called, self
is actually the function print_x
. Obviously adding things to self
won't change your instance of Test
because self
isn't an instance of Test
:-). In other words, there is nothing special about defining the decorator function inside the class. The only thing that it does is it also adds a function _change_x
to the namespace that you could call at other times.
How do we get this working then? Well, the answer is to realize that _change_x
is only decorating methods. In that case, the first argument to the wrapper function will be self
(just like in a normal method), so we can drop it in there and work with it inside of wrapped
: This works:
class Test(object):
def __init__(self):
self.x = 5
def _change_x(f):
print "in _change_x"
def wrapped(self, *args, **kwargs):
print "in wrapped"
print args, kwargs
self.x = 8
return f(self, *args, **kwargs)
return wrapped
@_change_x
def print_x(self):
print "in print_x, x: %d" % self.x
return self.x
if __name__ == "__main__":
test = Test()
print "Initial value for x: %d" % test.x
print "Test if it changed? x: %d" % test.print_x()
But it turns out that you don't need to define the decorator in the class at all. After all, as I said earlier -- There is nothing special about putting it in the class...:
def _change_x(f):
print "in _change_x"
def wrapped(self, *args, **kwargs):
print "in wrapped"
print args, kwargs
self.x = 8
return f(self, *args, **kwargs)
return wrapped
class Test(object):
def __init__(self):
self.x = 5
@_change_x
def print_x(self):
print "in print_x, x: %d" % self.x
return self.x
if __name__ == "__main__":
test = Test()
print "Initial value for x: %d" % test.x
print "Test if it changed? x: %d" % test.print_x()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With