For some context to the question - I am using lazy loading to defer full initialization of certain properties in a class until the point at which they are needed (if at all) as they can be computationally expensive to calculate.
My question is - in python if when calculating the value of the property an error occurs, or the value can't be calculated, is raising an exception acceptable or is it an objectively bad idea?
I am aware of this question: Best practices: throwing exceptions from properties - and actually reworded this question after going over the points in it.
However I am really looking for a definitive answer with regards to python. For example should a getter always return a value even if that value is None? In other languages, such as c#, there are clear recommendations on how to design properties.
AVOID throwing exceptions from property getters.
Property getters should be simple operations and should not have any preconditions. If a getter can throw an exception, it should probably be redesigned to be a method. Notice that this rule does not apply to indexers, where we do expect exceptions as a result of validating the arguments
http://msdn.microsoft.com/en-us/library/ms229006.aspx
Would the same be true in python? Should this property really be a method? I can see how in a strongly typed language such as c# this could be an issue but am not really sure if the holds true here. Testing in the debugger it works as expected.
To be clear I am testing something like the following.
class A(object):
def __init__(self):
self.__x = None
@property
def x(self):
if not self.__x:
self.__x = calculate_x()
if not some_test(self.__x):
# Is this a bad idea?
raise ValueError('Get x error {}'.format(self.__x))
return self.__x
@x.setter
def x(self, value):
if not some_test(value):
raise ValueError('Set x error {}'.format(value))
self.__x = value
I have been RTFM and a lot about properties but can't seem to see anything that either uses it or else warns against it. Is this all perfectly acceptable or have I created some kind of monstrous antipattern from hell?
The reason I am trying this is because I was think of something like a "lazy" descriptor that allows me to quickly markup properties. e.g.
from functools import wraps
class Descriptor(object):
def __init__(self, func):
self.func = func
def __get__(self, obj, type=None):
value = self.func(obj)
setattr(obj, self.func.__name__, value)
return value
def lazy(func):
return wraps(func)(Descriptor(func))
then
class A(object):
def __init__(self):
self.__x = None
@lazy
def x(self):
# where calculate_x might raise an exception
return calculate_x()
After more reading and coming back to this I am going to answer my own question and say no - this is not recommended based on the PEP 8 Style Guide.
https://www.python.org/dev/peps/pep-0008/
Note 3: Avoid using properties for computationally expensive operations;
the attribute notation makes the caller believe that access is (relatively)
cheap.
I realise this is paraphrasing Christian's answer somewhat - but I was looking for some kind of official documentation or guidance on this kind of pattern.