Add Properties to Instances?
Bengt Richter
bokr at oz.net
Mon Mar 14 17:18:41 EST 2005
On 14 Mar 2005 13:07:29 -0800, "Martin Miller" <ggrp1.20.martineau at dfgh.net> wrote:
>Bengt Richter wrote, in part:
>> On 14 Mar 2005 01:19:23 -0800, "Martin Miller"
><ggrp1.20.martineau at 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/Descriptor.htm#invoking-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
More information about the Python-list
mailing list