Dynamically creating class properties

Discussion in 'Python' started by Karlo Lozovina, Oct 4, 2007.

  1. Hi all,

    this is my problem: lets say I have a arbitrary long list of attributes
    that I want to attach to some class, for example:

    l = ['item1', 'item2', 'item3']

    Using metaclasses I managed to create a class with those three
    attributes just fine. But now I need those attributes to be properties,
    so for example if 'A' is my constructed class, and 'a' an instance of
    that class:

    a = A()

    Now if I write:

    a.item1 = 'something'
    print a.item1

    I want it to be actually:

    a.setitem1('something')
    print a.getitem1

    Any idea how to do that with metaclasses and arbitrary long list of
    attributes? I just started working with them, and it's driving me nuts :).

    Thanks for the help,
    best regards.

    --
    Karlo Lozovina -- Mosor
     
    Karlo Lozovina, Oct 4, 2007
    #1
    1. Advertising

  2. Karlo Lozovina

    Paul Hankin Guest

    On Oct 4, 9:59 pm, Karlo Lozovina <_karlo_@_mosor.net> wrote:
    > Hi all,
    >
    > this is my problem: lets say I have a arbitrary long list of attributes
    > that I want to attach to some class, for example:
    >
    > l = ['item1', 'item2', 'item3']
    >
    > Using metaclasses I managed to create a class with those three
    > attributes just fine. But now I need those attributes to be properties,
    > so for example if 'A' is my constructed class, and 'a' an instance of
    > that class:
    >
    > a = A()
    >
    > Now if I write:
    >
    > a.item1 = 'something'
    > print a.item1
    >
    > I want it to be actually:
    >
    > a.setitem1('something')
    > print a.getitem1
    >
    > Any idea how to do that with metaclasses and arbitrary long list of
    > attributes? I just started working with them, and it's driving me nuts :).


    No metaclasses, but how about this?

    def make_class(name, attributes):
    # Build class dictionary.
    d = dict(_attributes=list(attributes))
    # Add in getters and setters from global namespace.
    for attr in attributes:
    d[attr] = property(globals()['get' + attr],
    globals()['set' + attr])
    # Construct our class.
    return type(name, (object,), d)


    # Test code:

    def getitem1(self):
    return self._fred + 1

    def setitem1(self, value):
    self._fred = value

    A = make_class('A', ['item1'])
    a = A()

    a.item1 = 19
    print a.item1

    >> 20



    You didn't say where the getters and setters (here 'getitem1',
    'setitem1', etc.) come from. I've assumed from the global namespace
    but you probably want to change that.

    --
    Paul Hankin
     
    Paul Hankin, Oct 4, 2007
    #2
    1. Advertising

  3. Karlo Lozovina

    Paul Hankin Guest

    On Oct 4, 11:55 pm, Paul Hankin <> wrote:
    > On Oct 4, 9:59 pm, Karlo Lozovina <_karlo_@_mosor.net> wrote:
    >
    >
    >
    > > Hi all,

    >
    > > this is my problem: lets say I have a arbitrary long list of attributes
    > > that I want to attach to some class, for example:

    >
    > > l = ['item1', 'item2', 'item3']

    >
    > > Using metaclasses I managed to create a class with those three
    > > attributes just fine. But now I need those attributes to be properties,
    > > so for example if 'A' is my constructed class, and 'a' an instance of
    > > that class:

    >
    > > a = A()

    >
    > > Now if I write:

    >
    > > a.item1 = 'something'
    > > print a.item1

    >
    > > I want it to be actually:

    >
    > > a.setitem1('something')
    > > print a.getitem1

    >
    > > Any idea how to do that with metaclasses and arbitrary long list of
    > > attributes? I just started working with them, and it's driving me nuts :).

    >
    > No metaclasses, but how about this?
    >
    > def make_class(name, attributes):
    > # Build class dictionary.
    > d = dict(_attributes=list(attributes))
    > # Add in getters and setters from global namespace.
    > for attr in attributes:
    > d[attr] = property(globals()['get' + attr],
    > globals()['set' + attr])
    > # Construct our class.
    > return type(name, (object,), d)


    Sorry, I'm adding '_attributes' unnecessarily to the class dictionary.
    The dictionary should be just initialised with d = {} before the
    properties are added.

    --
    Paul Hankin
     
    Paul Hankin, Oct 5, 2007
    #3
  4. Karlo Lozovina wrote:

    >
    > Any idea how to do that with metaclasses and arbitrary long list of
    > attributes? I just started working with them, and it's driving me nuts :).
    >
    > Thanks for the help,
    > best regards.
    >

    Try implementing a property factory function before worrying about the
    metaclass. Assuming you need a standard getter and setter, then the following
    (untested) example may be useful. If you need custom get/set behavior then you
    would rewrite the factory to accept passed-in functions.

    >>> def make_data_property(cls, prop_name):

    ...
    ... # create default methods that get and set a 'private' instance
    ... # attribute
    ... def _set(self, value):
    ... setattr(self, "_%s" % prop_name, value)
    ... def _get(self):
    ... # None is default. Alternatively handle AttributeError
    ... return getattr(self, "_%s" % prop_name, None)
    ...
    ... setattr(cls, prop_name, property(_get, _set))
    ...
    ... # optionally, fix the internal names of the _get and _set for better
    ... # introspection
    ... _set.func_name = setname = "set%s" % prop_name
    ... _get.func_name = getname = "get%s" % prop_name
    ...
    ... # optionally, make _get and _set members of the class, if you want to
    ... # call them directly (but then, why have the property?)
    ... setattr(cls, setname, _set)
    ... setattr(cls, getname, _get)
    ...
    >>> class A(object):

    ... pass
    ...
    >>> a=A()
    >>> a.item1

    Traceback (most recent call last):
    File "<input>", line 1, in <module>
    AttributeError: 'A' object has no attribute 'item1'
    >>> make_data_property(A,"item1")
    >>> a.item1
    >>> a.item1 = 42
    >>> a.item1

    42
    >>> make_data_property(A,"item2")
    >>> a.item2
    >>> a.item2 = 43
    >>>
    >>> a.item2

    43
    >>>


    If you can get this piece working, then multiple attributes should be easy.
    Then, if you like, you can call your property factory from the metaclass
    __init__ method.

    HTH
    Michael
     
    Michael Spencer, Oct 5, 2007
    #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. E11
    Replies:
    1
    Views:
    4,887
    Thomas Weidenfeller
    Oct 12, 2005
  2. SuperZE
    Replies:
    5
    Views:
    354
    SuperZE
    Oct 6, 2008
  3. steven

    creating a BED properties class with web services

    steven, Dec 4, 2007, in forum: ASP .Net Web Services
    Replies:
    2
    Views:
    120
    steven
    Dec 6, 2007
  4. Andy Dingley

    Dynamically creating properties?

    Andy Dingley, Oct 27, 2011, in forum: Python
    Replies:
    8
    Views:
    250
    DevPlayer
    Oct 30, 2011
  5. Shak Shak
    Replies:
    1
    Views:
    98
    David A. Black
    Jun 30, 2009
Loading...

Share This Page