By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,676 Members | 2,262 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,676 IT Pros & Developers. It's quick & easy.

Add Properties to Instances?

P: n/a
I'm trying to create some read-only instance specific properties, but
the following attempt didn't work:
class Foobar(object):
pass

foobar = Foobar()
foobar.x = property(fget=lambda: 42)

print "foobar.x:", foobar.x
Which results in the following ouput instead of '42':
foobar.x: <property object at 0x00AE57B0>

I also tried this: foobar.__dict__['x'] = property(fget=lambda: 42)

but get the same behavior.

Can anyone tell me what's wrong with this approach (and perhaps the
correct way to do it, if there is one)?

TIA,
Martin

Jul 18 '05 #1
Share this Question
Share on Google+
10 Replies


P: n/a
Martin Miller wrote:
I'm trying to create some read-only instance specific properties, but
the following attempt didn't work:

class Foobar(object):
pass

foobar = Foobar()
foobar.x = property(fget=lambda: 42)

print "foobar.x:", foobar.x

[snip]
Can anyone tell me what's wrong with this approach (and perhaps the
correct way to do it, if there is one)?


Properties cannot be defined on a per-instance basis. Properties must
be defined at the class level. So you need to do something like:

py> class Foobar(object):
.... x = property(fget=lambda self: 42)
....
py> Foobar().x
42

or

py> class Foobar(object):
.... pass
....
py> Foobar.x = property(fget=lambda self: 42)
py> Foobar().x
42

If you want to have different properties on different instances, you'll
need to make each of the different instances a different subtype of
Foobar, e.g.:

py> class Foobar(object):
.... pass
....
py> foobar = type('FoobarSub', (Foobar,),
.... dict(x=property(fget=lambda self: 42)))()
py> foobar.x
42
py> Foobar().x
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
AttributeError: 'Foobar' object has no attribute 'x'

What's the situation in which you think you want different properties
for different instances of the same class?

STeVe
Jul 18 '05 #2

P: n/a
On Sat, 12 Mar 2005 09:48:42 -0800, Martin Miller wrote:
I'm trying to create some read-only instance specific properties, but the
following attempt didn't work:


I'm going to echo Steven's comment: "What's the situation in which you
think you want different properties for different instances of the same
class?"

Another thought would be a custom __setattr__ and a bit of support:

Python 2.3.5 (#1, Mar 3 2005, 17:32:12)
[GCC 3.4.3 (Gentoo Linux 3.4.3, ssp-3.4.3-0, pie-8.7.6.6)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
import sets
class ReadOnlyAttributes(object): .... def __init__(self):
.... self.__dict__['_readOnly'] = sets.Set()
.... def addReadOnly(self, key, value):
.... setattr(self, key, value)
.... self._readOnly.add(key)
.... def __setattr__(self, key, value):
.... if key in self._readOnly:
.... raise AttributeError("can't set attribute")
.... self.__dict__[key] = value
.... r = ReadOnlyAttributes()
r.a = 22
r.a 22 r.a = 23
r.a 23 r.addReadOnly("a", 22)
r.a 22 r.a = 23 Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 9, in __setattr__
AttributeError: can't set attribute r.addReadOnly("a", 23) Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 5, in addReadOnly
File "<stdin>", line 9, in __setattr__
AttributeError: can't set attribute


I don't guarantee this completely fits the bill but I'm sure you can adapt
it from here.

Also note that, strictly speaking, you can't make a "true" read-only
attribute, only one that alerts a programmer if they try the simple way.
In a pure-Python object, there is always a way in. This shouldn't worry
you if you're using Python ("We're all consenting adults here"), but you
should also be aware of that. That said, this is certainly useful in the
real world.
Jul 18 '05 #3

P: n/a
So far a couple of people have asked:
What's the situation in which you think you want different properties
for different instances of the same class?


Fair enough -- here goes:

Essentially what I'm doing is implementing (yes, yet another ;-)
'enumeration' class using an an approach which involves an instance
factory function which returns a customized version of a predefined
generic '_Enum' class instance.

It does this by first creating an instance of the generic class and
then adds attributes (enumerator ids and corresponding values among
others) to it which are specific to the enumeration being created. This
all works pretty well, but I would like to make the values associated
with the ids immutable -- through normal means, at least.

It's not feature complete, but I would be happy post the current code
if there is interest in more of the details. Meanwhile, I'm going to
study the replies so far and think about the whole issue (and design) a
little more.

Thanks to all who have replied,
Martin

Jul 18 '05 #4

P: n/a
On 12 Mar 2005 09:48:42 -0800, "Martin Miller" <gg****************@dfgh.net> wrote:
I'm trying to create some read-only instance specific properties, but
the following attempt didn't work:
class Foobar(object):
pass

foobar = Foobar()
foobar.x = property(fget=lambda: 42)

print "foobar.x:", foobar.x


Which results in the following ouput instead of '42':
foobar.x: <property object at 0x00AE57B0>

I also tried this:
foobar.__dict__['x'] = property(fget=lambda: 42)

but get the same behavior.

Can anyone tell me what's wrong with this approach (and perhaps the
correct way to do it, if there is one)?

One way is to doctor the instance attribute access to do what
happens with a property when it is implemented normally as an
attribute of the class. E.g., (using InstProp in place of your Foobar)
class InstProp(object): ... def __getattribute__(self, attr):
... p = object.__getattribute__(self, attr)
... if isinstance(p, property): return p.__get__(self)
... return p
... import time
inst1 = InstProp()
inst2 = InstProp()
inst1.t = property(lambda self: time.ctime())
inst2.p2 = property(lambda self: 'prop2')
inst1.t 'Sat Mar 12 19:10:40 2005' inst2.p2

'prop2'

If you want robust writeable and/or deleteable properties, you will have
to do a little more work, but it can be done.

Regards,
Bengt Richter
Jul 18 '05 #5

P: n/a
On Sun, 13 Mar 2005 03:18:51 GMT, bo**@oz.net (Bengt Richter) wrote:
On 12 Mar 2005 09:48:42 -0800, "Martin Miller" <gg****************@dfgh.net> wrote:
I'm trying to create some read-only instance specific properties, but
the following attempt didn't work:
class Foobar(object):
pass

foobar = Foobar()
foobar.x = property(fget=lambda: 42)

print "foobar.x:", foobar.x


Which results in the following ouput instead of '42':
foobar.x: <property object at 0x00AE57B0>

I also tried this:
foobar.__dict__['x'] = property(fget=lambda: 42)

but get the same behavior.

Can anyone tell me what's wrong with this approach (and perhaps the
correct way to do it, if there is one)?

One way is to doctor the instance attribute access to do what
happens with a property when it is implemented normally as an
attribute of the class. E.g., (using InstProp in place of your Foobar)
class InstProp(object): ... def __getattribute__(self, attr):
... p = object.__getattribute__(self, attr)
... if isinstance(p, property): return p.__get__(self)
... return p
...

Actually, checking for being a property instance is more restrictive than
normal default processing. Checking for __get__ would be better.

This would let you use a function as an instance-specific method as well,
since functions have __get__ methods, and that is how they become bound
methods etc. We'll also pass the type of the instance, to give __get__
everything it needs for a proper bound method.
class InstProp(object): ... def __getattribute__(self, attr):
... p = object.__getattribute__(self, attr)
... if hasattr(p, '__get__'): return p.__get__(self, type(self))
... return p
... inst = InstProp()
def bar(self, *args): print 'bar method called with %r'% (args,) ... inst.bar = bar
inst.bar <bound method InstProp.bar of <__main__.InstProp object at 0x02EF1E8C>> inst.baz = lambda self: 'baz method'

inst.baz <bound method InstProp.<lambda> of <__main__.InstProp object at 0x02EF1E8C>> inst.baz() 'baz method' inst.p = property(lambda self: 'property p')
inst.p

'property p'

Regards,
Bengt Richter
Jul 18 '05 #6

P: n/a
In answer to my question about instance properties not working, Bengt
Richter suggest using:
>> class InstProp(object): ... def __getattribute__(self, attr):
... p = object.__getattribute__(self, attr)
... if isinstance(p, property): return p.__get__(self)
... return p
and more generally for any descriptor object:
>>> class InstProp(object):

... def __getattribute__(self, attr):
... p = object.__getattribute__(self, attr)
... if hasattr(p, '__get__'): return p.__get__(self,

type(self)) ... return p
Both the above makes the '__get__' method of any property attributes of
the instance to be used. However, it does not cause attempts to be made
to access their "__set__' methods when assigning to them (which should
fail in my case because my properties don't have such a method because
they are read-only).

Just overriding '__getattribute__' alone is insufficent to make
instance property/descriptor attributes fully function. To do so also
requires overriding the __setattr__ method so it checks for a '__set__'
method and then uses it if one is found (or delegates it to
object.__setattr__ if not).

Similarily, an override for '__delattr__' would also be need for
complete property functionality, I believe.

For just making instance attributes read-only, it seems to be that the
simplist solution would be to override __setattr__ and make it check to
see if the attribute is write protected or not, which is really all I
need for the specific task I'm trying to accomplish (which is
esstentially what Jeremy Bowers said in his reply).

What still puzzles me, though, is why all the above to make properties
work on instances is necessary in the first place. It's certainly not
clear (to me) from what is said in the How-to at:

http://users.rcn.com/python/download...ng-descriptors
I suspect that it may be simply a performance issue, in other words, it
was considered too slow to check for instance property/discriptors --
although *why* is not clear to me.

Best Regards,
Martin

Jul 18 '05 #7

P: n/a
On 14 Mar 2005 01:19:23 -0800, "Martin Miller" <gg****************@dfgh.net> wrote:
In answer to my question about instance properties not working, Bengt
Richter suggest using:
> >>> class InstProp(object):
> ... def __getattribute__(self, attr):
> ... p = object.__getattribute__(self, attr)
> ... if isinstance(p, property): return p.__get__(self)
> ... return p
and more generally for any descriptor object:
>>> class InstProp(object): ... def __getattribute__(self, attr):
... p = object.__getattribute__(self, attr)
... if hasattr(p, '__get__'): return p.__get__(self,

type(self))
... return p


Both the above makes the '__get__' method of any property attributes of
the instance to be used. However, it does not cause attempts to be made
to access their "__set__' methods when assigning to them (which should
fail in my case because my properties don't have such a method because
they are read-only).

Just overriding '__getattribute__' alone is insufficent to make
instance property/descriptor attributes fully function. To do so also
requires overriding the __setattr__ method so it checks for a '__set__'
method and then uses it if one is found (or delegates it to
object.__setattr__ if not).

Similarily, an override for '__delattr__' would also be need for
complete property functionality, I believe.

As I said in my first post,
"""
If you want robust writeable and/or deleteable properties, you will have
to do a little more work, but it can be done.
"""

I'm still leaving it as an exercise ;-)
For just making instance attributes read-only, it seems to be that the
simplist solution would be to override __setattr__ and make it check to
see if the attribute is write protected or not, which is really all I
need for the specific task I'm trying to accomplish (which is
esstentially what Jeremy Bowers said in his reply).

What still puzzles me, though, is why all the above to make properties
work on instances is necessary in the first place. It's certainly not
clear (to me) from what is said in the How-to at:

http://users.rcn.com/python/download...ng-descriptors
I suspect that it may be simply a performance issue, in other words, it
was considered too slow to check for instance property/discriptors --
although *why* is not clear to me.


I suspect the desired semantics re precedence have evolved to make normal
programs easily implementable, and that probably drove the implementation:
"""
For objects, the machinery is in object.__getattribute__ which transforms
b.x into type(b).__dict__['x'].__get__(b, type(b)).
The implementation works through a precedence chain that gives (my added [1,2,3])

[1] data descriptors priority over instance variables,
[2] instance variables priority over non-data descriptors,
[3] and assigns lowest priority to __getattr__ if provided.

The full C implementation can be found in PyObject_GenericGetAttr() in Objects/object.c.
"""

Regards,
Bengt Richter
Jul 18 '05 #8

P: n/a
Bengt Richter wrote, in part:
On 14 Mar 2005 01:19:23 -0800, "Martin Miller" <gg****************@dfgh.net> wrote, in part:
What still puzzles me, though, is why all the above to make propertieswork on instances is necessary in the first place. It's certainly notclear (to me) from what is said in the How-to at:

http://users.rcn.com/python/download...ng-descriptors
I suspect that it may be simply a performance issue, in other words,
itwas considered too slow to check for instance property/discriptors --although *why* is not clear to me.


I suspect the desired semantics re precedence have evolved to make

normal programs easily implementable, and that probably drove the implementation: """
For objects, the machinery is in object.__getattribute__ which transforms b.x into type(b).__dict__['x'].__get__(b, type(b)).
The implementation works through a precedence chain that gives (my added [1,2,3])

[1] data descriptors priority over instance variables,
[2] instance variables priority over non-data descriptors,
[3] and assigns lowest priority to __getattr__ if provided.

The full C implementation can be found in PyObject_GenericGetAttr() in Objects/object.c.
"""
I haven't examined the C code in Objects/object.c to see *how* the
semantics are implemented because that's not really the point...which
is the descriptions of what's suppose to happen don't seem to match
what actually does. To illustrate, consider: class Foobar(object):
pass

def myget(self, obj, type=None):
return 42

def myset(self, value):
raise AttributeError("this is a read-only property")

foobar = Foobar()
foobar.x = property(myget, myset)

print "foobar.x:", foobar.x
Which prints: foobar.x: <property object at 0x00AE5850>
Ignoring "why" issue, my question becomes:

foobar.x is a data descriptor property, however object.__getattribute__
does *not* seem to be treating it as such and handling it the way
described either by you or in what is written in the how-to.
Specifically the statements that: For objects, the machinery is in object.__getattribute__ which transforms b.x into type(b).__dict__['x'].__get__(b, type(b)).


This doesn't seem to be occuring. Am I missing something?

Thanks,
Martin

Jul 18 '05 #9

P: n/a
On 14 Mar 2005 13:07:29 -0800, "Martin Miller" <gg****************@dfgh.net> wrote:
Bengt Richter wrote, in part:
On 14 Mar 2005 01:19:23 -0800, "Martin Miller"<gg****************@dfgh.net>
wrote, in part:
>What still puzzles me, though, is why all the above to makeproperties >work on instances is necessary in the first place. It's certainlynot >clear (to me) from what is said in the How-to at:
>>


http://users.rcn.com/python/download...ng-descriptors
>I suspect that it may be simply a performance issue, in other words,it >was considered too slow to check for instance property/discriptors-- >although *why* is not clear to me.


I suspect the desired semantics re precedence have evolved to make

normal
programs easily implementable, and that probably drove the

implementation:
"""
For objects, the machinery is in object.__getattribute__ which

transforms
b.x into type(b).__dict__['x'].__get__(b, type(b)).
The implementation works through a precedence chain that gives (my

added
[1,2,3])

[1] data descriptors priority over instance variables,
[2] instance variables priority over non-data descriptors,
[3] and assigns lowest priority to __getattr__ if provided.

The full C implementation can be found in PyObject_GenericGetAttr()

in
Objects/object.c.
"""


I haven't examined the C code in Objects/object.c to see *how* the
semantics are implemented because that's not really the point...which
is the descriptions of what's suppose to happen don't seem to match
what actually does. To illustrate, consider:
class Foobar(object):
pass

def myget(self, obj, type=None):
return 42

def myset(self, value):
raise AttributeError("this is a read-only property")

foobar = Foobar()
foobar.x = property(myget, myset)

print "foobar.x:", foobar.x


Which prints:
foobar.x: <property object at 0x00AE5850>


Ignoring "why" issue, my question becomes:

foobar.x is a data descriptor property, however object.__getattribute__

It is a property, and it has the requisite methods (__get__ and __set__) to be
a data descriptor, but it is not a data descriptor unless it is visible as
an attribute of type(foobar), which foobar.x is not.
does *not* seem to be treating it as such and handling it the way
described either by you or in what is written in the how-to.
Specifically the statements that:
For objects, the machinery is in object.__getattribute__ which

transforms
b.x into type(b).__dict__['x'].__get__(b, type(b)).


This doesn't seem to be occuring. Am I missing something?

I think so. Following your example:
class Foobar(object): ... pass
... def myget(self, obj, type=None): ... return 42
... def myset(self, value): ... raise AttributeError("this is a read-only property")
... foobar = Foobar()
foobar.x = property(myget, myset)
print "foobar.x:", foobar.x foobar.x: <property object at 0x02EF0644>
type(foobar).__dict__['x'] Traceback (most recent call last):
File "<stdin>", line 1, in ?
KeyError: 'x'

meaning
b.x into type(b).__dict__['x'].__get__(b, type(b)).
does not apply, and the attempt to get foobar.x falls back to
ordinary attribute access. I.e., foobar.x will be whatever

BTW, I'm not sure type(b).__dict__['x'].__get__(b, type(b))
is really fully correct, since that would not find foobar.x in a Foobar base class:
class Base(object): pass ... Base.x = property(myget, myset)
class Sub(Base): pass ... sub = Sub()
sub.x Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: myget() takes at least 2 arguments (1 given)

(At least it was found, even if the signature is bad ;-)

But:
type(sub).__dict__['x']

Traceback (most recent call last):
File "<stdin>", line 1, in ?
KeyError: 'x'

So the real truth chases down the mro chain before giving up
and falling back to ordinary attribute access, IWT.

Regards,
Bengt Richter
Jul 18 '05 #10

P: n/a
Bengt Richter wrote:
On 14 Mar 2005 13:07:29 -0800, "Martin Miller" <gg****************@dfgh.net> wrote:
Bengt Richter wrote, in part:
On 14 Mar 2005 01:19:23 -0800, "Martin Miller"<gg****************@dfgh.net>
wrote, in part:
>What still puzzles me, though, is why all the above to make

properties
>work on instances is necessary in the first place. It's certainly

not
>clear (to me) from what is said in the How-to at:
>>
http://users.rcn.com/python/download...ng-descriptors
>I suspect that it may be simply a performance issue, in other
words,it
>was considered too slow to check for instance
property/discriptors--
>although *why* is not clear to me.

I suspect the desired semantics re precedence have evolved to make

normal
programs easily implementable, and that probably drove the

implementation:
"""
For objects, the machinery is in object.__getattribute__ which

transforms
b.x into type(b).__dict__['x'].__get__(b, type(b)).
The implementation works through a precedence chain that gives (my

added
[1,2,3])

[1] data descriptors priority over instance variables,
[2] instance variables priority over non-data descriptors,
[3] and assigns lowest priority to __getattr__ if provided.

The full C implementation can be found in
PyObject_GenericGetAttr()in
Objects/object.c.
"""


I haven't examined the C code in Objects/object.c to see *how* the
semantics are implemented because that's not really the point...whichis the descriptions of what's suppose to happen don't seem to match
what actually does. To illustrate, consider:
class Foobar(object):
pass

def myget(self, obj, type=None):
return 42

def myset(self, value):
raise AttributeError("this is a read-only property")

foobar = Foobar()
foobar.x = property(myget, myset)

print "foobar.x:", foobar.x


Which prints:
foobar.x: <property object at 0x00AE5850>


Ignoring "why" issue, my question becomes:

foobar.x is a data descriptor property, however

object.__getattribute__ It is a property, and it has the requisite methods (__get__ and __set__) to be a data descriptor, but it is not a data descriptor unless it is visible as an attribute of type(foobar), which foobar.x is not.
does *not* seem to be treating it as such and handling it the way
described either by you or in what is written in the how-to.
Specifically the statements that:
For objects, the machinery is in object.__getattribute__ whichtransforms
b.x into type(b).__dict__['x'].__get__(b, type(b)).


This doesn't seem to be occuring. Am I missing something?

I think so. Following your example:
>>> class Foobar(object): ... pass
... >>> def myget(self, obj, type=None): ... return 42
... >>> def myset(self, value): ... raise AttributeError("this is a read-only property")
... >>> foobar = Foobar()
>>> foobar.x = property(myget, myset)
>>> print "foobar.x:", foobar.x foobar.x: <property object at 0x02EF0644> >>>
>>> type(foobar).__dict__['x'] Traceback (most recent call last):
File "<stdin>", line 1, in ?
KeyError: 'x'

meaning
b.x into type(b).__dict__['x'].__get__(b, type(b)).
does not apply, and the attempt to get foobar.x falls back to
ordinary attribute access. I.e., foobar.x will be whatever

BTW, I'm not sure type(b).__dict__['x'].__get__(b, type(b))
is really fully correct, since that would not find foobar.x in a

Foobar base class: >>> class Base(object): pass ... >>> Base.x = property(myget, myset)
>>> class Sub(Base): pass ... >>> sub = Sub()
>>> sub.x Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: myget() takes at least 2 arguments (1 given)

(At least it was found, even if the signature is bad ;-)

But:
>>> type(sub).__dict__['x']
Traceback (most recent call last):
File "<stdin>", line 1, in ?
KeyError: 'x'

So the real truth chases down the mro chain before giving up
and falling back to ordinary attribute access, IWT.

Regards,
Bengt Richter


Ah, from your comments and explanation I think I finally understand
that the description in the docs *is* in fact accurate -- and
indirectly, the reason for properties on instances not working by
default. Specifically I was not realizing that the "type(b).__dict__"
in the statement: b.x is tranformed into type(b).__dict__['x'].__get__(b, type(b))

implys that no check for 'x' in made in "b.__dict__".

Now I'm back to wondering "why" because it would be relatively easy to
check for a descriptor in the instance dictionary first -- and would be
more "Pythonic", IMHO, since instances can generally augment (or
override) that which is defined by their class.

Thank you for bearing with me on this somewhat obtuse follow-on
question regarding properties and descriptors (and to the everyone else
for their suggestions for work-arounds).

Best regards,
Martin

P.S. After looking at the implementation of PyObject_GenericGetAttr()
in Objects/object.c, I believe your observation about the
"type(b).__dict__['x'].__get__(b, type(b))" not being fully correct is
true. Instead, there appears to be a search being done through the mro
base classes of type(b). Perhaps that fact could be used to create
"mix-in" style classes with the desired properties...

Jul 18 '05 #11

This discussion thread is closed

Replies have been disabled for this discussion.