Dynamic property names on class

Discussion in 'Python' started by Bryan, Nov 13, 2009.

  1. Bryan

    Bryan Guest

    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?
     
    Bryan, Nov 13, 2009
    #1
    1. Advertising

  2. 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
     
    Diez B. Roggisch, Nov 13, 2009
    #2
    1. Advertising

  3. Bryan

    Bryan Guest

    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.
     
    Bryan, Nov 13, 2009
    #3
  4. 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
     
    Diez B. Roggisch, Nov 13, 2009
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Paddy McCarthy
    Replies:
    3
    Views:
    715
    Anthony J Bybell
    Sep 24, 2004
  2. Bob
    Replies:
    1
    Views:
    385
    Lucas Tam
    Jul 30, 2004
  3. E11
    Replies:
    1
    Views:
    4,781
    Thomas Weidenfeller
    Oct 12, 2005
  4. Ares Lagae
    Replies:
    8
    Views:
    450
    Ares Lagae
    Sep 24, 2004
  5. Martin Boese

    Dynamic class names

    Martin Boese, Apr 2, 2008, in forum: Ruby
    Replies:
    4
    Views:
    129
    Martin Boese
    Apr 2, 2008
Loading...

Share This Page