Dynamic property names on class

Diez B. Roggisch deets at nospam.web.de
Fri Nov 13 20:46:54 CET 2009


Bryan schrieb:
> On Nov 13, 9:34 am, "Diez B. Roggisch" <de... at nospam.web.de> wrote:
>> Bryan schrieb:
>>
>>
>>
>>> I have several properties on a class that have very similar behavior.
>>> If one of the properties is set, all the other properties need to be
>>> set to None.  So I wanted to create these properties in a loop like:
>>> class Test(object):
>>>    for prop in ['foo', 'bar', 'spam']:
>>>            # Attribute that data is actually stored in
>>>            field = '_' + prop
>>>            # Create getter/setter
>>>            def _get(self):
>>>                    return getattr(self, field)
>>>            def _set(self, val):
>>>                    setattr(self, field, val)
>>>                    for otherProp in prop:
>>>                            if otherProp != prop: setattr(self, '_' + otherProp, None)
>>>            # Assign property to class
>>>            setattr(Test, prop, property(_get, _set))
>>> t = Test()
>>> t.foo = 1
>>> assert t.bar == t.spam == None
>>> But the class Test is not defined yet, so I can't set a property on
>>> it.  How can I do this?
>> With a metaclass, or a post-class-creation function. Which is a
>> metaclass without being fancy.
>>
>> Just put your above code into a function with the class in question as
>> argument, and invoke it after Test is defined.
>>
>> Diez
> 
> I think there are some closure issues with this as I am getting very
> strange results.  I think all properties have the getter/setters of
> whatever the last item in the list was.
> t.foo = 'settingFoo' actually sets t.spam, as 'spam' was the last
> property generated.

That's a FAQ. Closures capture the *names*, not the values. There are 
various options to remedy this, e.g. by something like this:


def gen_property(prop):

     def _get(...) # your code


     return property(_get, _set)

setattr(Test, prop, gen_property(prop))


Diez



More information about the Python-list mailing list