Adding properties to objects

M

Matthew Barnes

Is it possible to add properties to objects dynamically?

I have an instance (x) of some new-style class (Foo), and I would like
to be able to do something like:

However, when I evaluate x.myproperty I get back a property object
(which makes sense). I get the feeling I'm missing a step to "bind"
the property object to the class instance.

Is this possible (it's Python... of course it's possible, right?), and
if so, how?

Matthew Barnes
 
J

John Roth

Matthew Barnes said:
Is it possible to add properties to objects dynamically?

I have an instance (x) of some new-style class (Foo), and I would like
to be able to do something like:


However, when I evaluate x.myproperty I get back a property object
(which makes sense). I get the feeling I'm missing a step to "bind"
the property object to the class instance.

Is this possible (it's Python... of course it's possible, right?), and
if so, how?

The property definition only lives in a class; you cannot add
a property to an instance by itself. Well, you can but it won't
be evaluated as a property by the default __getattribute__()
magic method.

To make a property work on an instance basis you'd have
to have a specialty __getattribute__() magic method in the
class. That's left as an exercise for the reader.

John Roth
 
P

Peter Otten

Matthew said:
Is it possible to add properties to objects dynamically?

I have an instance (x) of some new-style class (Foo), and I would like
to be able to do something like:


However, when I evaluate x.myproperty I get back a property object
(which makes sense). I get the feeling I'm missing a step to "bind"
the property object to the class instance.

Is this possible (it's Python... of course it's possible, right?), and
if so, how?

Fresh from the mad coders' department, here's how to dynamically change an
object's class to get the desired effect:

import new
class Foo(object):
def __setattr__(self, name, value):
if isinstance(value, property):
klass = new.classobj(self.__class__.__name__, (self.__class__,),
{})
setattr(klass, name, value)
self.__class__ = klass
else:
object.__setattr__(self, name, value)


f1 = Foo()
f1.name = "first"

def set1(self, v):
self.name = v[1:-1]
def get1(self):
return "(%s)" % self.name
f1.prp = property(get1, set1)

f2 = Foo()
f2.name = "second"

def set2(self, v):
self.name = v[2:-2]
def get2(self):
return "<<%s>>" % self.name
f2.prp = property(get2, set2)

print f1.prp, f2.prp
f2.prp = "((was second))"
print f1.prp, f2.prp
f2.__class__.prp = f1.__class__.prp
print f1.prp, f2.prp


If you try the above approach, you will of course end up with more classes
than instances - if you only expect a limited number of dynamic properties
you could put all combinations into a class cache.

:)

Peter
 
M

Matthew Barnes

Is it possible to add properties to objects dynamically?

So the impression I'm getting is that it's *possible* but not really
intended, otherwise there would be better support in the core
language. Fair statement?

I'll take that as a clue that there's probably a cleaner approach to
the problem I'm trying to solve.

The feedback was informative... thank you all!

Matthew Barnes
 
S

Shalabh Chaturvedi

You can add properties dynamically, but to the type (i.e. 'class') and
not the instance (i.e. 'object'). For your example:
.... print a,b
....
This property will work for *all* instances of Foo.
So the impression I'm getting is that it's *possible* but not really
intended, otherwise there would be better support in the core
language. Fair statement?

I don't see any reason why dynamically adding properties to the *type*
is not intended. It's not complicated and works fine.
I'll take that as a clue that there's probably a cleaner approach to
the problem I'm trying to solve.

What is the problem you are trying to solve?
The feedback was informative... thank you all!

Matthew Barnes

HTH,
Shalabh
 
M

Matthew Barnes

Shalabh Chaturvedi said:
You can add properties dynamically, but to the type (i.e. 'class') and
not the instance (i.e. 'object'). For your example:

... print a,b
...

This property will work for *all* instances of Foo.

Right. I may not have been clear, but I was trying to add different
properties to different *instances* of Foo.
What is the problem you are trying to solve?

Here's basically what I was trying to do:

class Foo(object):

def __init__(self, sourcedict):
# sourcedict is a dictionary of objects having get() and set()
# methods. Nevermind where sourcedict comes from. The point
# is that different instances get different sourcedict's.
for name, object in sourcedict.items():
# This doesn't do what I had hoped for.
# My thinking was flawed on several levels.
self.__dict__['name'] = property(object.get, object.set)

So suppose "sourcedict" has some object named "bar". The idea was to
create properties on-the-fly based on the contents of "sourcedict",
such that:
x = Foo(sourcedict) # Given this...
x.bar # would invoke sourcedict['bar'].get()
x.bar = 1 # would invoke sourcedict['bar'].set(1)

I've since realized that properties are not the right approach for
something like this, and that I would be better off with a more
straight-forward approach using custom Foo.__getattr__ and
Foo.__setattr__ methods (seems obvious now that I've simplified the
problem description :).

Matthew Barnes
 

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,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top