FAQ
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?

Search Discussions

  • Diez B. Roggisch at Nov 13, 2009 at 5:34 pm

    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
  • Bryan at Nov 13, 2009 at 6:20 pm

    On Nov 13, 9:34?am, "Diez B. Roggisch" 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.
  • Diez B. Roggisch at Nov 13, 2009 at 7:46 pm

    Bryan schrieb:
    On Nov 13, 9:34 am, "Diez B. Roggisch" 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

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedNov 13, '09 at 4:59p
activeNov 13, '09 at 7:46p
posts4
users2
websitepython.org

2 users in discussion

Diez B. Roggisch: 2 posts Bryan: 2 posts

People

Translate

site design / logo © 2022 Grokbase