import functools
class Decor(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
def closure(*args, **kwargs):
print args, kwargs
return self.func(*args, **kwargs)
return closure(*args, **kwargs)
class Victim(object):
@Decor
def sum(self, a, b):
return a+b
v = Victim()
v.sum(1, 2)
Results in:
(1, 2) {}
Traceback (most recent call last):
File "test.py", line 19, in <module>
v.sum(1, 2)
File "test.py", line 11, in __call__
return closure(*args, **kwargs)
File "test.py", line 10, in closure
return self.func(*args, **kwargs)
TypeError: sum() takes exactly 3 arguments (2 given)
How do I get self
argument for the method?
UPDATE:
I've managed to create a more useful adaptation of Martijn's answer, which returns Decor
object in response to __get__
, but at the same time binds self
argument, when it is called as a method of object. With this version you can say e.g. Victim.sum.hooks.append(my_favorite_function)
and my_favorite_function
will be called before Victim.sum
. WARNING: this version is thread-unsafe.
class Decor(object):
def __init__(self, func):
self.func = func
self.hooks = []
wraps(self.func)(self)
def __get__(self, instance, klass):
if instance != None: self.instance = instance
if klass != None: self.klass = klass
return self
def __call__(self, *args, **kwargs):
def closure(*args, **kwargs):
for function in self.hooks:
function(*args, **kwargs)
func = self.func
retval = func(*args, **kwargs) #kwargs_copy #called with notify = False
return retval
return closure.__get__(self.instance, self.klass)(*args, **kwargs)