Dynamically creating class properties

K

Karlo Lozovina

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.
 
P

Paul Hankin

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


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.
 
P

Paul Hankin

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:
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.
 
M

Michael Spencer

Karlo said:
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.
...
... # 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)
... ... pass
... Traceback (most recent call last):

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top