how to add property "dynamically"?

A

akonsu

hello,

i need to add properties to instances dynamically during run time.
this is because their names are determined by the database contents.
so far i found a way to add methods on demand:

class A(object) :
def __getattr__(self, name) :
if name == 'test' :
def f() : return 'test'
setattr(self, name, f)
return f
else :
raise AttributeError("'%s' object has no attribute '%s'" %
(self.__class__.__name__, name))

this seems to work and i can invoke method test() on an object. it
would be nice to have it as property though. so i tried:

class A(object) :
def __getattr__(self, name) :
if name == 'test' :
def f() : return 'test'
setattr(self, name, property(f))
return f
else :
raise AttributeError("'%s' object has no attribute '%s'" %
(self.__class__.__name__, name))

but this does not work, instance.test returns a callable but does not
call it.

i am not an expert in python, would someone please tell me what i am
doing wrong?

thanks
konstantin
 
C

Christian Heimes

akonsu said:
i am not an expert in python, would someone please tell me what i am
doing wrong?

You can't add properties to an instance. They must be specified on the
type (aka new style class). Descriptors and magic methods are only
looked up on classes for various reasons - mostly performance reasons.
Old style classes behave differently but properties don't work with old
style classes.

You can archive the same behavior by hooking into __getattr__,
__setattr__ and __delattr__. Mind the speed penelty, though!

Christian
 
B

Bruno Desthuilliers

akonsu a écrit :
hello,

i need to add properties to instances dynamically during run time.
this is because their names are determined by the database contents.
so far i found a way to add methods on demand:

class A(object) :
def __getattr__(self, name) :
if name == 'test' :
def f() : return 'test'
setattr(self, name, f)
return f
else :
raise AttributeError("'%s' object has no attribute '%s'" %
(self.__class__.__name__, name))
> this seems to work and i can invoke method test() on an object.

Nope. This adds per-instance *function* attributes - not *methods*.

class A(object) :
def __getattr__(self, name) :
if name == 'test' :
def f(self) :
return "%s.test" % self
setattr(self, name, f)
return f
else :
raise AttributeError(
"'%s' object has no attribute '%s'" \
% (self.__class__.__name__, name)
)


a = A()
a.test()
=> Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes exactly 1 argument (0 given)


To add methods on a per-instance basis, you have to manually invoke the
descriptor protocol's implementation of function objects:

class A(object) :
def __getattr__(self, name) :
if name == 'test' :
def f(self) :
return "%s.test" % self
m = f.__get__(self, type(self))
setattr(self, name, m)
return m
else :
raise AttributeError(
"'%s' object has no attribute '%s'" \
% (self.__class__.__name__, name)
)

it
would be nice to have it as property though. so i tried:

class A(object) :
def __getattr__(self, name) :
if name == 'test' :
def f() : return 'test'
setattr(self, name, property(f))
return f
else :
raise AttributeError("'%s' object has no attribute '%s'" %
(self.__class__.__name__, name))

but this does not work, instance.test returns a callable but does not
call it.

Properties must be class attributes. The only way (the only way I know)
to get them to work as instance-attributes is to overload
__getattribute__, which is tricky and may have pretty bad impact on
lookup perfs - and ruins the whole point of using properties FWIW.
i am not an expert in python, would someone please tell me what i am
doing wrong?

Wrong solution to your problem, I'd say. Let's start again:

"""
> i need to add properties to instances dynamically during run time.
> this is because their names are determined by the database contents.
"""

Care to elaborate ? I may be wrong, but I suspect you're trying to roll
your own python/database mapper. If so, there are quite a couple Python
ORMs around. Else, please tell us more.
 

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

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top