Set and Get @property method in Python by string variable
attributes, descriptor, python
Solution
Calling `getattr(model_class, model_attribute)` will return the property object that `model_attribute` refers to. I'm assuming you already know this and are trying to access the value of the property object.
class A(object):
def __init__(self):
self._myprop = "Hello"
@property
def myprop(self):
return self._myprop
@myprop.setter
def myprop(self, v):
self._myprop = v
prop = getattr(A, "myprop")
print prop
# <property object at 0x7fe1b595a2b8>
Now that we have obtained the property object from the class we want to access its value. Properties have three methods `fget`, `fset`, and `fdel` that provide access to the `getter`, `settter`, and `deleter` methods defined for that property.
Since `myprop` is an instance method, we'll have to create an instance so we can call it.
print prop.fget
# <function myprop at 0x7fe1b595d5f0>
print prop.fset
# <function myprop at 0x7fe1b595d668>
print prop.fdel # We never defined a deleter method
# None
a = A()
print prop.fget(a)
# Hello
Problem
Currently I have a generalized function where you can pass in an attribute name and a class (it would also work with specific object instances, but I am using classes), and the function will look up and operate on that attribute by calling ``` getattr(model_class, model_attribute) ``` and it will modify the attribute by calling (on an object instance this time) settattr(model_obj, key, value) However, I have a class where we have an `@property` method defined instead of a simple attribute, and `setattr` does not work. How do I dynamically get the `@property` based on a string name for that property method? Perhaps I could use `__dict__` but that seems dirty and not as safe. Edit: example code The generalized function ``` def process_general(mapping, map_keys, model_class, filter_fn, op_mode=op_modes.UPDATE): """ Creates or updates a general table object based on a config dictionary. `mapping`: a configuration dictionary, specifying info about the table row value `map_keys`: keys in the mapping that we use for the ORM object `model_class`: the ORM model class we use the config data in `op_mode`: the kind of operation we want to perform (delete, update, add, etc.) Note that relationships between model objects must be defined and connected outside of this function. """ # We construct a dictionary containing the values we need to set arg_dict = make_keyword_args(map_keys, mapping) # if we are updating, then we must first check if the item exists # already if (op_mode == op_modes.UPDATE): # Find all rows that match by the unique token. # It should only be one, but we will process all of them if it is the # case that we didn't stick to the uniqueness requirement. matches = filter_fn() # Keep track of the length of the iterator so we know if we need to add # a new row num_results = 0 for match in matches: # and we set all of the object attributes based on the dictionary set_attrs_from_dict(match, arg_dict) model_obj = match num_results += 1 # We have found no matches, so just add a new row if (num_results < 1): model_obj = model_class(**arg_dict) return model_obj # TODO add support for other modes. This here defaults to add else: return model_class(**arg_dict) ``` An example class passed in: ``` class Dataset(db.Model, UserContribMixin): # A list of filters for the dataset. It can be built into the dataset filter form dict # in get_filter_form. It's also useful for searching. filters = db.relationship('DatasetFilter', backref='dataset') # private, and retrieved from the @property = select _fact_select = db.relationship('DatasetFactSelect', order_by='DatasetFactSelect.order') @property def fact_select(self): """ FIXME: What is this used for? Appears to be a list of strings used to select (something) from the fact model in the star dataset interface. :return: List of strings used to select from the fact model :rtype: list """ # these should be in proper order from the relationship order_by clause sels = [sel.fact_select for sel in self._fact_select] return sels ```