3

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).

2
  • 1
    One related and quite famous SO page is How to add property to a python class dynamically? and another with an interesting answer from @AlexMartelli is Dynamically adding \@property in python. Commented Jun 16, 2016 at 21:12
  • 1
    I found those pages in trying to figure this out and they helped but they didn't do exactly what I wanted, which was to define the properties in the __init__ so they existed for all instances. Commented Jun 16, 2016 at 21:16

3 Answers 3

1

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
Sign up to request clarification or add additional context in comments.

Comments

1

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.

1 Comment

You could post that over at codereview.stackexchange.com to see if anyone can help you tighten it up at all.
0

Try namedtuple

from collections import namedtuple

my_par = namedtuple('par', 'name value')
par = my_par('par_name', 'par_value')
print(par[0]) #outputs: par_name
print(par.value) #outputs: par_value
name, value = par
print(name,value) #outputs: par_name par_value

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.