I have an object that describes a dataset with multiple required pieces of data and metadata. The different data and metadata elements are themselves objects of the same type with a number of different attributes, including a name and a value attribute. Most of the interactions with these data elements are with the value attribute and it has become annoying to constantly reference it using .value, so I am trying to define a property for each data element, but I want to do it programmatically so when I add a new data element it automatically gets a property defined for it. To be specific, here is some example code:
class my_par(object):
def __init__(self, name, value):
self.name = name
self.value = value
class my_obj(object):
def __init__(self, xval, yval, zval):
self.xval = my_par('x', xval)
self.yval = my_par('y', yval)
self.zval = my_par('z', zval)
I can make properties on the my_obj class using
@property
def x(self):
return self.xval.value
@x.setter
def x(self, value):
self.xval.value = value
but I want a way to do it programmatically over all the my_par type objects. (I already have an iterator over those objects, so all I need is the code to define properties programmatically).
In python, there are functions getattr and setattr that can get and set properties of objects. It's used like this:
setattr(obj, "prop", value) # set the value
getattr(obj, "prop") # get the value
After trying a lot of things that didn't work, this did:
class my_par(object):
def __init__(self, name, value):
self.name = name
self.value = value
class my_obj(object):
def __init__(self, xval, yval, zval):
self.xval = my_par('x', xval)
self.yval = my_par('y', yval)
self.zval = my_par('z', zval)
par_list = ['xval', 'yval','zval']
for p in par_list:
this_par = getattr(self, p)
attr_name = this_par.name
setattr(self.__class__, attr_name, property(self.prop_fget(p), self.prop_fset(p)))
def prop_fget(self, attr_name):
def fget(self):
this_par = getattr(self, attr_name)
return this_par.value
return fget
def prop_fset(self, attr_name):
def fset(self, value):
this_par = getattr(self, attr_name)
this_par.value = value
setattr(self, attr_name, this_par)
return fset
Note in particular the use of self.__class__ in setattr in order to attach the property to the class rather than the instance.
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