I create a class whose objects are initialized with a bunch of XML code. The class has the ability to extract various parameters out of that XML and to cache them inside the object state variables. The potential amount of these parameters is large and most probably, the user will not need most of them. That is why I have decided to perform a "lazy" initialization.
In the following test case such a parameter is title
. When the user tries to access it for the first time, the getter function parses the XML, properly initializes the state variable and return its value:
class MyClass(object):
def __init__(self, xml=None):
self.xml = xml
self.title = None
def get_title(self):
if self.__title is None:
self.__title = self.__title_from_xml()
return self.__title
def set_title(self, value):
self.__title = value
title = property(get_title, set_title, None, "Citation title")
def __title_from_xml(self):
#parse the XML and return the title
return title
This looks nice and works fine for me. However, I am disturbed a little bit by the fact that the getter function is actually a "setter" one in the sense that it has a very significant side effect on the object. Is this a legitimate concern? If so, how should I address it?
I agree with the idea that getters/settings shouldn't have side effects, but I would say that they shouldn't have non-obvious side effects. As far as throwing exceptions, if you are setting a property to an invalid value (in a very basic sense), then validation exceptions are fine.
Getter and setter methods (also known as accessors) are dangerous for the same reason that public fields are dangerous: They provide external access to implementation details. What if you need to change the accessed field's type? You also have to change the accessor's return type.
A side effect is a change in the system state or an observable interaction with the outside world, in other words, outside that function. Here's a list of things that a function should not do to avoid side effects. It shouldn't mutate shared state. It shouldn't mutate its input arguments.
This design pattern is called Lazy initialization and it has legitimate use.
While the getter certainly performs a side-effect, that's not traditionally what one would consider a bad side-effect. Since the getter always returns the same thing (barring any intervening changes in state), it has no user-visible side-effects. This is a typical use for properties, so there's nothing to be concerned about.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With