Reputation: 1203
Given a class definition that allows 3 possible inputs:
class FooBar(object):
def __init__(self, x=None, y=None, z=None):
if x is not None:
self.x = x
elif if y is not None:
self.y = y
elif if z is not None:
self.z = z
else:
raise ValueError('Please supply either x,y or z')
This 3 inputs are related each other, lets say:
x = .5*y = .25*z
This also implies:
y = .5*z = 2*x
and
z = 2*y = 4*x
When creating a instance of FooBar()
, the user need to supply one of those and the __init__
takes care of it.
Now I would like to do the following
To try to accomplish that I did:
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
self._y = 2*self._x
self._z = 4*self._x
And to the others:
@property
def y(self):
return self._y
@y.setter
def y(self, value):
self._y = value
self._x = .5*self._y
self._z = 2*self._y
@property
def z(self):
return self._z
@z.setter
def z(self, value):
self._z = value
self._x = .25*self._z
self._y = .5*self._z
Is this the correct approach?
Upvotes: 1
Views: 50
Reputation: 476659
I think you make this more complicated than you have to. If the variables are related, and one can fully be determined by the other, there is no need to store three variables. You can store one variable, and dynamically calculate the others. Like:
class Foo(object):
def __init__(self, x=None, y=None, z=None):
if x is not None:
self.x = x
elif x is not None:
self.y = y
elif z is not None:
self.z = z
else:
raise ValueError('Provide an x, y, or z value.')
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = x
@property
def y(self):
return self._x / 2.0
@y.setter
def y(self, value):
self._x = 2 * value
@property
def z(self):
return self._x / 4.0
@z.setter
def z(self, value):
self._x = 4 * value
We thus store only a _x
attribute on the class, and all the rest of the getters and setters, use the _x
attribute (we can of course use _y
or _z
instead).
Furthermore something that is not very elegant is that a programmer can instantiate a Foo(x=1, y=425)
. As you can see, that means that it contains inconsistency. Perhaps it is worth raising an error in that case.
You can ensure that you only have one parameter provided by adding the following check in the init module:
class Foo(object):
def __init__(self, x=None, y=None, z=None):
data = [i for i in [x, y, z] if i is not None]
if len(data) > 1:
raise ValueError('Multiple parameters provided.')
if x is not None:
self.x = x
elif x is not None:
self.y = y
elif z is not None:
self.z = z
else:
raise ValueError('Provide an x, y, or z value.')
# ...
Here we thus construct a list of all non-None
values, if there is more than one, the programmer provided two or more values, and then it is better to raise an exception.
Upvotes: 2