In my code (python) I have a class defined as follows:
class Properties:
def __init__(self,**kwargs):
self.otherproperty = kwargs.get("otherproperty")
self.channel = kwargs.get("channel")
if self.channel not in "A":
print("bad channel input - it should be A")
pass
In the rest of my code, in various places I calculate and add various attributes to the instance of that class:
prop = Properties()
prop.channel="B"
#lots of calculations here
prop.otherproperty= "not a channel"
But when I do it this way, I get an error: TypeError: 'in <string>' requires string as left operand, not NoneType
I already figured out that the following way I have no issues, and the new attribute gets nicely validated, and the user is informed that prop.channel
should be different :
prop = Properties(otherproperty = "not a channel",channel="B")
But because of several reasons it would be inconvenient to define prop
object this way.
So how do I validate the object's attributes when I'm adding them step-by-step? And how is such step-by-step object building professionally named?
You can define a custom setter for the channel property with Python descriptors:
class Properties:
def __init__(self, **kwargs):
self.otherproperty = kwargs.get("otherproperty")
self._channel = None # Private attribute for channel
@property
def channel(self):
return self._channel
@channel.setter
def channel(self, value):
if value not in "A":
raise ValueError("Bad channel input, it must be a substring of 'A'")
self._channel = value
The example usage would be:
prop = Properties()
prop.channel = "B" # Raises ValueError
This way of gradually adding attributes to an object can be called "lazy object initialization" and is useful if you want to avoid long computations before creating an object.
Side note: the above code doesn't raise an error if you set prop.channel = ""
. So you might want to change the validation to if value != "A":
if this was an unintended behavior.