1

Is there any way to set a property in Python using a function call instead of the "a.x = value" syntax?

Explanation: There is a class that I didn't write. I have to query and set various pieces of data from this class. Most of the items have setter and getter functions, like getA() and setA(value). But a few of the items have been declared as properties. I have some code where I get the setter function of the various items, so that I can loop over them. But It does not work for properties because there is not a setter function.

class DataObject(object):
 def __init__(self, data, setterFunc):
 super(DataObject, self).__init__()
 self._data = data
 self._setterFunc = setterFunc
 @property
 def data(self):
 return self._data
 @data.setter
 def data(self, value):
 if self._setterFunc:
 self._data = value
 self._setterFunc(value)
foo = SomeClassIDidNotWrite()
objectList = []
objectList.append(DataObject(foo.getA(), foo.setA))
objectList.append(DataObject(foo.getB(), foo.setB))
# objectList.append(DataObject(foo.c, foo.c)) <-- This does not work
for dataObj in objectList:
 dataObj.data = 5
asked May 1, 2014 at 20:57

2 Answers 2

3

You can set attributes dynamically with the setattr() function; this applies to attributes that are really properties too.

You can create a setter with a lambda function or with functools.partial():

objectList.append(DataObject(foo.c, lambda val: setattr(foo, 'c', val)))

or

from functools import partial
objectList.append(DataObject(foo.c, partial(setattr, foo, 'c')))
answered May 1, 2014 at 20:59
Sign up to request clarification or add additional context in comments.

Comments

1

@MartijnPieters answer is the way to go if possible, but if you need to try to dynamically derive the setters, you can also access the property's descriptor on the class directly, providing the instance as an argument.

foo = SomeClassIDidNotWrite()
SomeClassIDidNotWrite.a.fset(foo, val)

Or even more dynamically:

attr_name = 'a'
getattr(foo.__class__, attr_name).fset(foo, val)

Combining this with your existing get/set code and wrapping it in try/except, you can create a generic handler for all the attributes you need to work with.

for attr_name in ('A', 'B', 'C'):
 try:
 getter = getattr(foo, 'get' + attr_name)
 setter = getattr(foo, 'set' + attr_name)
 except AttributeError:
 descriptor = getattr(foo.__class__, attr_name)
 getter = functools.partial(descriptor.fget, foo)
 setter = functools.partial(descriptor.fset, foo)
 objectList.append(DataObject(getter, setter))
answered May 1, 2014 at 21:07

1 Comment

Interesting. I don't need to get this generic for my specific case, but I did not know something like this was possible.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.