I apologise if the title is cryptic, I could not think of a way to describe my problem in a sentence. I am building some code in python2.7 that I describe below.
Minimal working example
My code has a Parameter
class that implements attributes such as name
and value
, which looks something like this.
class Parameter(object):
def __init__(self, name, value=None, error=None, dist=None, prior=None):
self.name = name
self._value = value # given value for parameter, this is going to be changed very often in an MCMC sampler
self.error = error # initial estimate of error for the parameter, will only be set once
self._dist = dist # a distribution for the parameter, will only be set once
self.prior = prior
@property
def value(self):
return self._value
@property
def dist(self):
return self._dist
The class also has several properties that returns the mean, median, etc. of Parameter.dist
if a distribution is given.
I have another class, e.g. ParameterSample
, that creates a population of different Parameter
objects. Some of these Parameter
objects have their attributes (e.g. value
, error
) set using the Parameter.set_parameter()
function, but some other Parameter
objects are not explicitly set, but their value
and dist
attributes depend on some of the other Parameter
objects that are set:
class ParameterSample(object):
def __init__(self):
varied_parameters = ('a', 'b') # parameter names whose `value` attribute is varied
derived_parameters = ('c',) # parameter names whose `value` attribute is varied, but depends on `a.value` and `b.value`
parameter_names = varied_parameters + derived_parameters
# create `Parameter` objects for each parameter name
for name in parameter_names:
setattr(self, name, Parameter(name))
def set_parameter(self, name, **kwargs):
for key, val in kwargs.items():
if key == 'value':
key = '_'.join(['', key]) # add underscore to set `Parameter._value`
setattr(getattr(self, name), key, val) # basically does e.g. `self.a.value = 1`
I can now create a ParameterSample
and use them like this:
parobj = ParameterSample()
parobj.set_parameter('a', value=1, error=0.1)
parobj.set_parameter('b', value=2, error=0.5)
parobj.a.value
>>> 1
parobj.b.error
>>> 0.5
parobj.set_parameter('b', value=3)
parobj.b.value
>>> 3
parobj.b.error
>>> 0.5
What I want
What I ultimately want, is to use Parameter.c
the same way. For example:
parobj.c.value
>>> 4 # returns parobj.a.value + parobj.b.value
parobj.c.dist
>>> None # returns a.dist + b.dist, but since they are not currently set it is None
c
therefore needs to be a Parameter
object with all the same attributes as a
and b
, but where its value
and dist
are updated according to the current attributes of a
and b
.
However, I should also mention that I want to be able to set the allowed prior ranges for parameter c
, e.g. parobj.set_parameter('c', prior=(0,10))
before making any calls to its value -- so c
needs to be an already defined Parameter
object upon the creation of the ParameterSample
object.
How would I implement this into my ParameterSample
class?
What I've tried
I have tried looking into making my own decorators, but I am not sure if that is the way to go since I don't fully understand how I would use those.
I've also considered adding a @property to c
that creates a new Parameter
object every time it is called, but I feel like that is not the way to go since it may slow down the code.
I should also note that the ParameterSample
class above is going to be inherited in a different class, so whatever the solution is it should be able to be used in this setting:
class Companion(ParameterSample)
def __init__(self, name):
self.name = name
super(Companion, self).__init__()
comp = Companion(name='Earth')
comp.set_parameter('a', value=1)
comp.set_parameter('b', value=3)
comp.c.value
>>> 4