Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to programmatically define properties in python

Tags:

python

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

like image 461
Bryna H Avatar asked Mar 06 '26 15:03

Bryna H


2 Answers

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
like image 157
Michael Zhang Avatar answered Mar 09 '26 03:03

Michael Zhang


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.

like image 38
Bryna H Avatar answered Mar 09 '26 03:03

Bryna H



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!