Class Decorator For Methods From Other Class
Solution 1:
Functions are descriptors and that's what allows them to auto-bind self. The easiest way to deal with this is to implement decorators using functions so that this is handled for you. Otherwise you need to explicitly invoke the descriptor. Here's one way:
import functools
class MyDecoratorClass:
def __init__(self, method):
functools.update_wrapper(self, method)
self.method = method
def __get__(self, instance, owner):
return type(self)(self.method.__get__(instance, owner))
def __call__(self, *args, **kwargs):
# do stuff before
retval = self.method(*args, **kwargs)
# do stuff after
return retval
class Foobar:
def __init__(self):
# initialize stuff
pass
@MyDecoratorClass
def foo(self, x, y):
print(f"{[self, x, y]=}")
@MyDecoratorClass
def bar(spam):
print(f"{[spam]=}")
Foobar().foo(1, 2)
bar(3)
Here the __get__ method creates a new instance of MyDecoratorClass with the bound method (previously self.method was just a function since no instance existed yet). Also note that __call__ just calls self.method(*args, **kwargs) - if self.method is now a bound method, the self of FooBar is already implied.
Solution 2:
You can implement the descriptor protocol, an example of how functions do it (but in pure python) is available in the Descriptor HOWTO, translated to your case:
import functools
import types
class MyDecoratorClass:
def __init__(self, func):
functools.update_wrapper(self, func)
self.func = func
def __call__(self, *args, **kwargs):
# do stuff before
retval = self.func(*args, **kwargs)
# do stuff after
return retval
def __get__(self, obj, objtype=None):
if obj is None:
return self
return types.MethodType(self, obj)
Note, return types.MethodType(self, obj) is essentially equivalent to
return lambda *args, **kwargs : self.func(obj, *args, **kwargs)
Note from Kristof
Could it be that you meant this:
return types.MethodType(self, obj)is essentially equivalent toreturn lambda *args, **kwargs : self(obj, *args, **kwargs)Note that I replaced
self.func(..)withself(..). I tried, and only this way I can ensure that the statements at# do stuff beforeand# do stuff afteractually run.
Post a Comment for "Class Decorator For Methods From Other Class"