Reputation: 160
I'm trying to apply a conditional decorator as described in another stackoverflow post, but I'd like the condition to be set from inside the class its being used. Instead I get a Reference error pointing that self is not defined.
class foo:
def __init__(self):
self.debug = True
@conditional_decorator(decorator, self.debug)
def function(self):
pass
I tried defining a global variable and updating it from inside the __init__() method but it kept its original value when called as an argument of the decorator.
debug = None
class foo:
def __init__(self):
self.debug = True
global debug
debug = self.debug
@conditional_decorator(decorator, debug)
def function(self):
pass
The only way it worked was declaring a global variable and setting it outside of the class.
How can I apply the value of the class property to the decorator?
Upvotes: 1
Views: 1128
Reputation: 530882
The decorator should not be conditional. Rather, when the decorated function is called, it should look at self.debug
to determine whether to use the original function or the wrapped part.
def conditional_decorator(dec):
def decorator(func):
def _(self, *args, **kwargs):
f = func
if self.debug:
f = dec(f)
return f(self, *args, **kwargs)
return _
return decorator
def decorator(f):
def _(*args, **kwargs):
print("Decorated")
return f(*args, **kwargs)
return _
class foo:
def __init__(self, debug):
self.debug = debug
@conditional_decorator(decorator)
def function(self):
print("foo stuff")
foo(True).function()
print("===")
foo(False).function()
outputs
Decorated
foo stuff
===
foo stuff
Upvotes: 1
Reputation: 39354
An update to the answer given by @Maurice Meyer which allows a member of the class to be nominated:
from functools import wraps
def conditional_decorator(decoration, member):
def decorator(method):
predecorated = decoration(method)
@wraps(method)
def wrapper(*args, **kwargs):
self = args[0]
condition = getattr(self, member)
if not condition:
return method(*args, **kwargs)
return predecorated(*args, **kwargs)
return wrapper
return decorator
#And used like this for example:
class foo:
def __init__(self, debug):
self.debug = debug
@conditional_decorator(decorator, "debug")
def function(self):
pass
f1 = foo(True)
f1.function()
Upvotes: 1
Reputation: 18106
This is how you make a decorator handle classes and arguments:
from functools import wraps
def conditional_decorator(param):
def real_decorator(fn):
@wraps(fn)
def wrapper(*args, **kw):
cls = args[0]
print(cls.debug)
print(param)
return wrapper
return real_decorator
class foo:
def __init__(self):
self.debug = True
@conditional_decorator('param1')
def function(self):
pass
f = foo()
f.function()
Output:
True
param1
Upvotes: 1