I was trying to learn about decorators, and was trying to write a decorator for a class that would wrap all the methods in the class (except the internal ones). I can see that it's trying to wrap the methods I want wrapped, but then when I try to call any of those methods, it seems that __init__()
was wrapped.
#!/usr/bin/python
import sys
import types
from functools import wraps
def classTracer(cls):
for name,f in vars(cls).items():
if isinstance(f, types.FunctionType) and not name.startswith('__'):
print "I am wrapping method", name
@wraps(f)
def wrapper(*args, **kwargs):
print "Entering %s()" % f.__name__
rval = f(*args, **kwargs)
print "Exited %s(), returning" % f.__name__, rval
return rval
setattr(cls, name, wrapper)
return cls
@classTracer
class MyClass(object):
def __init__(self):
self.x = 1
def foo(self, i):
return i+7
def bar(self, i):
return i-7
def main():
print 'create object'
x = MyClass()
print 'call bar'
print x.bar(7)
return 0
if __name__ == "__main__":
sys.exit(main())
The output:
I am wrapping method bar
I am wrapping method foo
create object
call bar
Entering __init__()
Traceback (most recent call last):
File "./test2.py", line 35, in <module>
sys.exit(main())
File "./test2.py", line 31, in main
print x.bar(7)
File "./test2.py", line 14, in wrapper
rval = f(*args, **kwargs)
TypeError: __init__() takes exactly 1 argument (2 given)
Where am I going wrong?
Edit: thanks to the linked question, I was able to modify my wrapper:
def classTracer(cls):
def gen_wrapper(name, f):
@wraps(f)
def wrapper(*args, **kwargs):
print "Entering %s()" % name
rval = f(*args, **kwargs)
print "Exited %s(), returning" % name, rval
return rval
return wrapper
for name,f in vars(cls).items():
if isinstance(f, types.FunctionType) and not name.startswith('__'):
print "I am wrapping method", name
setattr(cls, name, gen_wrapper(name, f))
print 'loop done, last function was', name
return cls