I'm trying to use custom wrappers/decorators in Python, and I'd like to declare one inside a class, so that I could for instance print a snapshot of the attributes. I've tried things from this question with no success.
Here is what I'd like to do (NB: this code doesn't work, I explain what happens below)
class TestWrapper():
def __init__(self, a, b):
self.a = a
self.b = b
self.c = 0
def enter_exit_info(self, func):
def wrapper(*arg, **kw):
print '-- entering', func.__name__
print '-- ', self.__dict__
res = func(*arg, **kw)
print '-- exiting', func.__name__
print '-- ', self.__dict__
return res
return wrapper
@enter_exit_info
def add_in_c(self):
self.c = self.a + self.b
print self.c
@enter_exit_info
def mult_in_c(self):
self.c = self.a * self.b
print self.c
if __name__ == '__main__':
t = TestWrapper(2, 3)
t.add_in_c()
t.mult_in_c()
The expected output is :
-- entering add_in_c
-- {'a': 2, 'b': 3, 'c': 0}
5
-- exiting add_in_c
-- {'a': 2, 'b': 3, 'c': 5}
-- entering mult_in_c
-- {'a': 2, 'b': 3, 'c': 5}
6
-- exiting mult_in_c
-- {'a': 2, 'b': 3, 'c': 6}
But I this code gives
Traceback (most recent call last):
File "C:\Users\cccvag\workspace\Test\src\module2.py", line 2, in <module>
class TestWrapper():
File "C:\Users\cccvag\workspace\Test\src\module2.py", line 18, in TestWrapper
@enter_exit_info
TypeError: enter_exit_info() takes exactly 2 arguments (1 given)
And if I try @enter_exit_info(self)
or @self.enter_exit_info
, I get a NameError
. What could I do?
EDIT:
I do not need above all to have the decorator physically declared inside the class, as long as it is able to access attributes from an instance of this class. I thought it could only be made by declaring it inside the class, Rawing's answer proved me wrong.
Classes as decorators In Python, decorators can be either functions or classes. In both cases, decorating adds functionality to existing functions. When we decorate a function with a class, that function becomes an instance of the class.
Decorators are a very powerful and useful tool in Python since it allows programmers to modify the behaviour of function or class.
In Python, the @classmethod decorator is used to declare a method in the class as a class method that can be called using ClassName. MethodName() . The class method can also be called using an object of the class. The @classmethod is an alternative of the classmethod() function.
To decorate a function with a class, we must use the @ syntax followed by our class name above the function definition. Following convention, we will use camel case for our class name. In the class definition, we define two methods — the init constructor and the magic (or dunder) call method.
You will need to handle self
explicitly.
class TestWrapper():
def __init__(self, a, b):
self.a = a
self.b = b
self.c = 0
def enter_exit_info(func):
def wrapper(self, *arg, **kw):
print '-- entering', func.__name__
print '-- ', self.__dict__
res = func(self, *arg, **kw)
print '-- exiting', func.__name__
print '-- ', self.__dict__
return res
return wrapper
@enter_exit_info
def add_in_c(self):
self.c = self.a + self.b
print self.c
@enter_exit_info
def mult_in_c(self):
self.c = self.a * self.b
print self.c
if __name__ == '__main__':
t = TestWrapper(2, 3)
t.add_in_c()
t.mult_in_c()
This is valid python, but it's somewhat weird to have a function at the class level which is not really a method. Unless you have a good reason to do it this way, it would be more idiomatic to move the decorator to module level scope.
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