I recently asked a question on StackOverflow, looking for a way to more easily turn a class attribute into a
@property, but only if no other value has been provided to the class constructor. A simple way to do this is
class Demo(object): def __init__(self, value=None): self._value = value @property def value(self): if self._value is None: # some calculations to get value self._value = value return self._value
which I considered quite some overhead, so my question there asked for a decorator implementing this, and I came up with this solution
import functools # https://stackoverflow.com/a/28961925/321973 def property_if_None_generator(f, cached=False): @functools.wraps(f) def wrapped(self): value = self.__getattribute__('_' + f.__name__) if value is not None: return value else: return f(self) if cached: wrapped = functools.lru_cache()(wrapped) return property(wrapped) property_if_None = lambda f: property_if_None_generator(f, cached=False) cached_property_if_None = lambda f: property_if_None_generator(f, cached=True)
then the question's example would turn into
class Demo(object): def __init__(self, value=None): self._value = value @chached_property_if_None def value(self): # some calculations to get value return value
Now I would appreciate any feedback on both the decorator itself and whether this is actually acceptable as opposed to the non-decorator version mentioned above. I'm especially concerned about the question whether it is a good idea to implicitly use the underscore-prepended attribute/property-name.
I have also considered making things even shorter by using another decorator (or even a metaclass) such that the
__init__ wouldn't even have to do the
self._value = value assignment, I'd also appreciate opinions on that.
edit Since the SO-answer merely received a downvote without comment so far, I'd really appreciate feedback on this...