I would like to declare properties in the constructor of my class.
The class MaterialOne shows how I have it currently. Every property has to be defined separately. However, I will have groups of similar properties, which I would like to give the same fset/fget/fdel.
Since it requires a lot of code to write all the properties explicit, I would like to define the properties in a more concise way. I therefore thought of letting the constructor handle this. Class MateralTwo shows how I have that in mind.
Unfortunately it doesn’t work, as I get TypeErrors:
TypeError: get_property() takes exactly 1 argument (2 given)
I can understand why it complains, but I can’t think of any solution. I don’t necessarily want to define the properties from a list in the constructor. What I am looking for is a more concise and clean method of defining them.
class MaterialOne(object):
def __init__(self):
pass;
def del_property(attr):
"""Abstract deller"""
def del_attr(self):
setattr(self, attr, None);
return del_attr
def set_property(attr):
"""Abstract setter."""
def set_attr(self, x):
setattr(self, attr, x);
return set_attr
def get_property(attr):
"""Abstract getter"""
def get_attr(self):
if getattr(self, attr) is not None:
return getattr(self, attr);
else:
return 'Some calculated value..'
return get_attr
_young = None;
_shear = None;
_poisson = None;
young = property(fget=get_property('_young'), fset=set_property('_young'), fdel=del_property('_young'));
shear = property(fget=get_property('_shear'), fset=set_property('_shear'), fdel=del_property('_shear'));
poisson = property(fget=get_property('_poisson'), fset=set_property('_poisson'), fdel=del_property('_poisson'));
class MaterialTwo(object):
def __init__(self):
properties = ['young', 'shear', 'poisson'];
self.create_properties(properties)
def del_property(attr):
"""Abstract deller"""
def del_attr(self):
setattr(self, attr, None);
return del_attr
def set_property(attr):
"""Abstract setter."""
def set_attr(self, x):
setattr(self, attr, x);
return set_attr
def get_property(attr):
"""Abstract getter"""
def get_attr(self):
if getattr(self, attr) is not None:
return getattr(self, attr);
else:
return 'Some calculated value..'
return get_attr
def create_properties(self, items):
for item in items:
storage = '_'+item;
setattr(self, storage, None);
setattr(self, item, property(fget=self.get_property(storage), fset=self.set_property(storage), fdel=self.del_property(storage)));
steel = MaterialOne();
steel.young = 2e11;
steel.poisson = 0.3;
print steel.poisson
print steel.shear
carbon = MaterialTwo();
carbon.young = 2e11;
carbon.poisson = 0.3;
print carbon.poisson
print carbon.shear
To clarify some more on the code. What I would like to write are Classes for materials, Solid, Liquid, Gas, each of them a subclass of Material. Many material properties will just be assigned. Some can be calculated based on which have been defined. Given two elastic moduli a third can be calculated for instance.
This I have implemented now using something quite similar as MaterialOne. However, as I am getting more material properties, and will also include more of these kind of calculations, I would like to make it cleaner, more organized. Writing it as I did in MaterialTwo is a possibility to me.
This is ultimately your problem. Since properties are descriptors, they must be bound to the class, not the instance. You will need to override
__getattr__(),__setattr__(), and__delattr__()and implement it there.