I have a python dataclass in which I want to conditionally assign certain decorators depending on some global variable.
The condition is checked at the top of the script, but for my example below, I've simply supplied the result of that checking. If the check is True
, I want to give those methods the @functools.cached_property
decorator. If it is False
, I just want them to receive the standard @property
decorator.
The issue I keep running into is that I can't quite figure out how (or if it's even possible) to make this work as a simple decorator. I mostly get errors about method objects when calling or manipulating test.x_times_y
, and I'm not sure if it is possible to write the function in such a way that calling test.x_times_y
in the example below actually yields the result that I want.
import functools
import dataclasses
_value_checked = False
def myDecorator(func):
def decorator(self):
if not _value_checked:
return property(func)(self)
else:
return functools.cached_property(func)(self)
return decorator
@dataclasses.dataclass
class MyClass():
x: int
y: int
z: int = 0
@myDecorator
def x_times_y(self):
return self.x*self.y
test = MyClass(5,6,7)
I'd also like to avoid getter and setter methods, so I'm hopeful that that is possible. I've looked at many answers on here (such as this one) but haven't been able to find an answers that actually works, as most don't apply to decorating methods. I'm using Python 3.8 for this.
The behavior you want can be implemented with a simple conditional assignment:
my_decorator = functools.cached_property if _value_checked else property
or
if _value_checked:
my_decorator = functools.cached_property
else:
my_decorator = property
If you need to do more complex logic at each use of the decorator, you can use a function that returns the decorator you want:
def my_decorator():
if not _value_checked:
return property
else
return functools.cached_property
No complex argument forwarding required. Just delegate to the decorators you already have.