Lets say my class has many function, and I want to apply my decorator on each one of them. I have researched for a while, and find https://stackoverflow.com/a/6307917/18859252. By using metaclass, I can decorate all function in one line. Here is my code (framework)
class myMetaClass(type):
def __new__(cls, name, bases, local):
for attr in local:
value = local[attr]
if callable(value) and attr != '__init__':
local[attr] = log_decorator(local['Variable'], value)
return super().__new__(cls, name, bases, local)
class log_decorator():
def __init__(self, Variable, func):
self.Variable = Variable
self.func = func
def __call__(self, *args, **kargs):
start_time = time.time()
self.func(*args, **kargs)
end_time = time.time()
class Test(metaclass = myMetaClass):
Variable = Some_Class
check_test = Some_Class
def __init__(self, **args):
self.connect = Some_Class(**args)
def A(self, a, b):
self.connect.abc
pass
then use like this
def Flow():
test = Test(**args)
test.A(a, b)
But here is problem, it show exception like:
TypeError:A() missing 1 required positional argument: 'self'
I have no idea about this problem. I'd be very grateful if anyone has an answer or if there is a better way.
The piece you are missing (and the bit I don't fully understand, but has to do with functions or methods as descriptors and how python will attach an instance as the self
parameter) is that log_decorator()
is an instance of that class and not a function or method (even though you have defined a __call__()
method which makes it callable.)
Here is some code which just slightly changes the syntax needed, but gives you the results you want:
import functools
class log_decorator:
def __init__(self, Variable): # Note that the only parameter is Variable
self.Variable = Variable
def __call__(self, func):
@functools.wraps(func)
def decorated(*args, **kwargs):
start_time = time.time()
func(*args, **kwargs)
end_time = time.time()
return decorated
class myMetaClass(type):
def __new__(cls, name, bases, local):
for attr in local:
value = local[attr]
if callable(value) and attr != '__init__':
# Note the change in syntax vvv
local[attr] = log_decorator(local['Variable'])(value)
return super().__new__(cls, name, bases, local)